1
22 小时以前 4f47f94957e67df0864930a2f638e9bdc8411b36
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/ReceiveMsgServiceImpl.java
@@ -18,6 +18,7 @@
import com.vincent.rsf.server.common.domain.BaseParam;
import com.vincent.rsf.server.common.domain.PageParam;
import com.vincent.rsf.server.manager.controller.dto.LocStockDto;
import com.vincent.rsf.server.manager.controller.params.OutStockToTaskParams;
import com.vincent.rsf.server.manager.controller.params.PakinItem;
import com.vincent.rsf.server.manager.controller.params.WaitPakinParam;
import com.vincent.rsf.server.manager.entity.*;
@@ -112,6 +113,8 @@
    private WarehouseAreasItemServiceImpl warehouseAreasItemService;
    @Autowired
    private LocItemService locItemService;
    @Autowired
    private OutStockService outStockService;
    /**
@@ -523,22 +526,51 @@
                    throw new CoolException("计划收货数量修改失败!!");
                }
                // 立即触发异步任务,不等待结果
                if (!Cools.isEmpty(palletId.get()) && StringUtils.isNotBlank(syncOrder.getOrderNo()) && !Cools.isEmpty(syncOrder.getStationId())) {
                    //组托
                    WaitPakinParam pakinParam = new WaitPakinParam();
                    pakinParam.setBarcode(palletId.get());
                    pakinParam.setStaNo(syncOrder.getStationId());
                if (!rule.equals(SerialRuleCode.SYS_OUT_STOCK_CODE)){
                    // 入库:联动组托
                    // 立即触发异步任务,不等待结果
                    if (!Cools.isEmpty(palletId.get()) && StringUtils.isNotBlank(syncOrder.getOrderNo()) && !Cools.isEmpty(syncOrder.getStationId())) {
                        //组托
                        WaitPakinParam pakinParam = new WaitPakinParam();
                        pakinParam.setBarcode(palletId.get());
                        pakinParam.setStaNo(syncOrder.getStationId());
                    boolean itemsCheck = waitPakinService.mergeItemsCheck(pakinParam, loginUserId);
                    if (itemsCheck) {
                        CompletableFuture.runAsync(() -> {
                            try {
                                asyncMergeItemsWcs(pakinParam, syncOrder.getOrderNo(), loginUserId);
                            } catch (Exception e) {
                                log.warn("订单 {} 开始自动组托", syncOrder.getOrderNo());
                        boolean itemsCheck = waitPakinService.mergeItemsCheck(pakinParam, loginUserId);
                        if (itemsCheck) {
                            CompletableFuture.runAsync(() -> {
                                try {
                                    asyncMergeItemsWcs(pakinParam, syncOrder.getOrderNo(), loginUserId);
                                } catch (Exception e) {
                                    log.warn("订单 {} 开始自动组托", syncOrder.getOrderNo());
                                }
                            });
                        }
                    }
                } else {
                    // 出库:指定出库
                    // 立即触发异步任务,不等待结果
                    if (!Cools.isEmpty(palletId.get()) && StringUtils.isNotBlank(syncOrder.getOrderNo()) && !Cools.isEmpty(syncOrder.getStationId())) {
                        Loc loc = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getBarcode, palletId.get()));
                        if (!Cools.isEmpty(loc)) {
                            //出库
                            List<OutStockToTaskParams> param = new ArrayList<>();
                            for (WkOrderItem wkOrderItem : orderItems){
                                OutStockToTaskParams outStockToTaskParams = new OutStockToTaskParams(wkOrderItem);
                                outStockToTaskParams.setLocCode(loc.getCode());
                                outStockToTaskParams.setSiteNo(syncOrder.getStationId());
                                param.add(outStockToTaskParams);
                            }
                        });
//                        boolean itemsCheck = waitPakinService.mergeItemsCheck(pakinParam, loginUserId);
//                            if (true) {
                            CompletableFuture.runAsync(() -> {
                                try {
                                    asyncOutboundExecutionWcs(param, wkOrder.getId(), loginUserId);
                                } catch (Exception e) {
                                    log.warn("订单 {} 开始自动出库", syncOrder.getOrderNo());
                                }
                            });
//                            }
                        }
                    }
                }
            });
@@ -577,6 +609,35 @@
            log.info("订单 {} 自动组托完成,共处理 {} 个项目", orderNo, param.getItems().size());
        } catch (Exception e) {
            log.error("订单 {} 自动组托失败: {}", orderNo, e.getMessage(), e);
        }
    }
    @Async
    public void asyncOutboundExecutionWcs(List<OutStockToTaskParams> param, Long orderId, Long loginUserId) {
        try {
//            int i = 0;
//            List<OutStockToTaskParams> tasks = new ArrayList<>();
//            while (true) {
//                tasks = new ArrayList<>();
//                i++;
//                if (i > 5) return;
//                Thread.sleep(3000);
//                for (OutStockToTaskParams taskParam : new OutStockToTaskParams[param.size()]) {
//                    if (StringUtils.isNotBlank(taskParam.getLocCode())) {
//                        tasks.add(taskParam);
//                    }
//                }
//                break;
//            }
            if (param.isEmpty()){
                log.warn("订单ID {} 没有找到可出库明细,跳过自动出库", orderId);
                return;
            }
            outStockService.genOutStockTask(param, loginUserId, orderId);
            log.info("订单ID {} 自动出库,共处理 {} 个明细", orderId, param.size());
        } catch (Exception e) {
            log.error("订单ID {} 自动出库: {}", orderId, e.getMessage(), e);
        }
    }
@@ -929,22 +990,25 @@
                return R.error("查询条件不能为空");
            }
            // 将ERP参数映射为Java实体字段名(驼峰格式),PageParam会自动转换为数据库字段名(下划线格式)
            // 将ERP参数映射为数据库字段名(下划线格式)
            Map<String, Object> queryMap = new HashMap<>();
            // 从实体类中提取查询条件,映射为数据库字段名
            // 从实体类中提取查询条件,映射为真实的数据库字段名
            if (StringUtils.isNotBlank(condition.getLocId())) {
                queryMap.put("locCode", condition.getLocId());
                queryMap.put("loc_code", condition.getLocId());
            }
            if (StringUtils.isNotBlank(condition.getMatNr())) {
                queryMap.put("matnrCode", condition.getMatNr());
                queryMap.put("matnr_code", condition.getMatNr());
            }
            if (StringUtils.isNotBlank(condition.getPlanNo())) {
                queryMap.put("trackCode", condition.getPlanNo());
                queryMap.put("track_code", condition.getPlanNo());
            }
            if (StringUtils.isNotBlank(condition.getBatch())) {
                queryMap.put("batch", condition.getBatch());
            }
            // 注意:orderNo 和 wareHouseId 不在 LocItem 表中,需要通过其他方式查询
            // orderNo 已在后面单独处理(plat_order_code 和 plat_work_code)
            // wareHouseId 需要通过 Loc 表关联查询,已在后面单独处理
            BaseParam baseParam = new BaseParam();
            baseParam.syncMap(queryMap);
@@ -953,10 +1017,27 @@
            QueryWrapper<LocItem> wrapper = pageParam.buildWrapper(false);
            // 订单号/工单号/MES工单号
            // 订单号可能存储在:1) LocItem.plat_order_code 2) LocItem.plat_work_code 3) WkOrder.code (通过orderId关联)
            if (StringUtils.isNotBlank(condition.getOrderNo())) {
                String orderNo = condition.getOrderNo();
                wrapper.and(w -> w.eq("plat_order_code", orderNo)
                        .or().eq("plat_work_code", orderNo));
                // 先查询WkOrder表,获取匹配的订单ID列表
                LambdaQueryWrapper<WkOrder> orderWrapper = new LambdaQueryWrapper<>();
                orderWrapper.eq(WkOrder::getCode, orderNo);
                List<WkOrder> matchingOrders = asnOrderService.list(orderWrapper);
                List<Long> matchingOrderIds = matchingOrders.stream()
                        .map(WkOrder::getId)
                        .collect(Collectors.toList());
                // 构建订单号查询条件:LocItem表的plat_order_code、plat_work_code,或通过orderId关联WkOrder.code
                wrapper.and(w -> {
                    w.eq("plat_order_code", orderNo)
                     .or().eq("plat_work_code", orderNo);
                    // 如果找到了匹配的订单,也查询orderId
                    if (!matchingOrderIds.isEmpty()) {
                        w.or().in("order_id", matchingOrderIds);
                    }
                });
            }
            // 物料组(需要通过物料表关联查询)
@@ -1180,4 +1261,186 @@
        return details;
    }
    /**
     * 库存查询汇总(供open-api调用)
     *
     * @param condition 查询条件实体类
     * @return 库存汇总列表
     */
    @Override
    public R erpQueryInventorySummary(InventoryQueryConditionParam condition) {
        try {
            // 参数验证
            if (condition == null) {
                return R.error("查询条件不能为空");
            }
            // 将ERP参数映射为数据库字段名(下划线格式)
            Map<String, Object> queryMap = new HashMap<>();
            // 从实体类中提取查询条件,映射为真实的数据库字段名
            if (StringUtils.isNotBlank(condition.getMatNr())) {
                queryMap.put("matnr_code", condition.getMatNr());
            }
            if (StringUtils.isNotBlank(condition.getPlanNo())) {
                queryMap.put("track_code", condition.getPlanNo());
            }
            if (StringUtils.isNotBlank(condition.getBatch())) {
                queryMap.put("batch", condition.getBatch());
            }
            BaseParam baseParam = new BaseParam();
            baseParam.syncMap(queryMap);
            PageParam<LocItem, BaseParam> pageParam = new PageParam<>(baseParam, LocItem.class);
            QueryWrapper<LocItem> wrapper = pageParam.buildWrapper(false);
            // 物料组(需要通过物料表关联查询)
            if (StringUtils.isNotBlank(condition.getMatGroup())) {
                // 调用物料Service查询物料组对应的物料ID列表(复用已有方法)
                LambdaQueryWrapper<Matnr> matnrWrapper = new LambdaQueryWrapper<>();
                matnrWrapper.eq(Matnr::getGroupId, condition.getMatGroup());
                List<Matnr> matnrs = matnrService.list(matnrWrapper);
                if (!matnrs.isEmpty()) {
                    List<Long> matnrIds = matnrs.stream().map(Matnr::getId).collect(Collectors.toList());
                    wrapper.in("matnr_id", matnrIds);
                } else {
                    // 如果没有找到物料,返回空结果
                    return R.ok().add(new ArrayList<>());
                }
            }
            // 只查询正常状态的库存(status=1表示正常)
            wrapper.eq("status", 1);
            // 设置分页参数,查询所有数据用于汇总
            pageParam.setCurrent(1);
            pageParam.setSize(Integer.MAX_VALUE);
            PageParam<LocItem, BaseParam> pageResult = locItemService.page(pageParam, wrapper);
            List<LocItem> locItems = pageResult.getRecords();
            if (locItems.isEmpty()) {
                return R.ok().add(new ArrayList<>());
            }
            // 获取所有需要关联的ID
            List<Long> locIds = locItems.stream()
                    .map(LocItem::getLocId)
                    .filter(Objects::nonNull)
                    .distinct()
                    .collect(Collectors.toList());
            List<Long> warehouseIds = new ArrayList<>();
            // 调用LocService查询库位信息(复用Service层方法)
            Map<Long, Loc> locMap = new HashMap<>();
            if (!locIds.isEmpty()) {
                List<Loc> locs = locService.listByIds(locIds);
                locMap = locs.stream().collect(Collectors.toMap(Loc::getId, loc -> loc));
                // 收集仓库ID
                warehouseIds = locs.stream()
                        .map(Loc::getWarehouseId)
                        .filter(Objects::nonNull)
                        .distinct()
                        .collect(Collectors.toList());
            }
            // 仓库编码过滤
            if (StringUtils.isNotBlank(condition.getWareHouseId())) {
                String wareHouseId = condition.getWareHouseId();
                LambdaQueryWrapper<Warehouse> whWrapper = new LambdaQueryWrapper<>();
                whWrapper.eq(Warehouse::getCode, wareHouseId);
                // 调用WarehouseService查询仓库信息(复用Service层方法)
                List<Warehouse> warehouses = warehouseService.list(whWrapper);
                if (!warehouses.isEmpty()) {
                    Long targetWarehouseId = warehouses.get(0).getId();
                    // 过滤库位,只保留目标仓库的库位
                    locMap = locMap.entrySet().stream()
                            .filter(entry -> Objects.equals(entry.getValue().getWarehouseId(), targetWarehouseId))
                            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
                    // 过滤locItems,只保留目标仓库的
                    Set<Long> validLocIds = locMap.keySet();
                    locItems = locItems.stream()
                            .filter(item -> item.getLocId() != null && validLocIds.contains(item.getLocId()))
                            .collect(Collectors.toList());
                    warehouseIds = Collections.singletonList(targetWarehouseId);
                } else {
                    return R.ok().add(new ArrayList<>());
                }
            }
            // 调用WarehouseService查询仓库信息(复用Service层方法)
            Map<Long, Warehouse> warehouseMap = new HashMap<>();
            if (!warehouseIds.isEmpty()) {
                List<Warehouse> warehouses = warehouseService.listByIds(warehouseIds);
                warehouseMap = warehouses.stream().collect(Collectors.toMap(Warehouse::getId, wh -> wh));
            }
            // 按仓库、物料、批号、库存组织分组汇总
            // 使用Map的key作为分组键:wareHouseId_matNr_batch_stockOrgId
            Map<String, Map<String, Object>> summaryMap = new HashMap<>();
            for (LocItem locItem : locItems) {
                // 获取仓库信息
                Loc loc = null;
                if (locItem.getLocId() != null) {
                    loc = locMap.get(locItem.getLocId());
                }
                if (loc == null) {
                    continue;
                }
                Warehouse warehouse = null;
                if (loc.getWarehouseId() != null && warehouseMap.containsKey(loc.getWarehouseId())) {
                    warehouse = warehouseMap.get(loc.getWarehouseId());
                }
                if (warehouse == null) {
                    continue;
                }
                // 构建分组键:wareHouseId_matNr_batch_stockOrgId
                String wareHouseId = warehouse.getCode();
                String matNr = locItem.getMatnrCode();
                String batch = locItem.getBatch() != null ? locItem.getBatch() : "";
                String stockOrgId = locItem.getUseOrgId() != null ? locItem.getUseOrgId() : "";
                String groupKey = wareHouseId + "_" + matNr + "_" + batch + "_" + stockOrgId;
                // 如果该分组已存在,累加数量
                if (summaryMap.containsKey(groupKey)) {
                    Map<String, Object> summary = summaryMap.get(groupKey);
                    Double currentAnfme = (Double) summary.get("anfme");
                    Double newAnfme = currentAnfme + (locItem.getAnfme() != null ? locItem.getAnfme() : 0.0);
                    summary.put("anfme", newAnfme);
                } else {
                    // 创建新的汇总记录
                    Map<String, Object> summary = new HashMap<>();
                    summary.put("wareHouseId", wareHouseId);
                    summary.put("wareHouseName", warehouse.getName());
                    summary.put("matNr", matNr);
                    summary.put("matTx", locItem.getMaktx());
                    summary.put("spec", locItem.getSpec());
                    summary.put("unit", locItem.getUnit());
                    summary.put("anfme", locItem.getAnfme() != null ? locItem.getAnfme() : 0.0);
                    summary.put("batch", locItem.getBatch());
                    summary.put("stockOrgId", locItem.getUseOrgId());
                    summary.put("planNo", locItem.getTrackCode());
                    summaryMap.put(groupKey, summary);
                }
            }
            // 转换为列表
            List<Map<String, Object>> result = new ArrayList<>(summaryMap.values());
            return R.ok().add(result);
        } catch (Exception e) {
            log.error("库存查询汇总失败", e);
            return R.error("查询失败:" + e.getMessage());
        }
    }
}