cl
2 天以前 a8a10ec2a3fe7d8db166413a92a34926fb178533
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java
@@ -55,6 +55,8 @@
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.client.HttpStatusCodeException;
import org.springframework.web.client.RestTemplate;
@@ -211,6 +213,7 @@
                    throw new CoolException("组托明细修执行数量修改失败!!");
                }
            });
            syncAsnOrderItemBarcodeByPakin(waitPakinItems, pakin.getBarcode(), loginUserId);
        });
        if (!waitPakinService.update(new LambdaUpdateWrapper<WaitPakin>()
@@ -301,6 +304,7 @@
                    throw new CoolException("组托明细修执行数量修改失败!!");
                }
            });
            syncAsnOrderItemBarcodeByPakin(waitPakinItems, pakin.getBarcode(), loginUserId);
        });
        if (!waitPakinService.update(new LambdaUpdateWrapper<WaitPakin>()
@@ -453,6 +457,7 @@
                    throw new CoolException("组托明细修执行数量修改失败!!");
                }
            });
            syncAsnOrderItemBarcodeByPakin(waitPakinItems, pakin.getBarcode(), loginUserId);
        });
        if (!waitPakinService.update(new LambdaUpdateWrapper<WaitPakin>()
@@ -463,6 +468,27 @@
            throw new CoolException("组拖状态修改失败!!");
        }
        return R.ok("任务生成完毕!");
    }
    /** 组托后将通知单明细条码回写为料箱码 */
    private void syncAsnOrderItemBarcodeByPakin(List<WaitPakinItem> waitPakinItems, String pakinBarcode, Long loginUserId) {
        if (waitPakinItems == null || waitPakinItems.isEmpty() || StringUtils.isBlank(pakinBarcode)) {
            return;
        }
        Set<Long> asnItemIds = waitPakinItems.stream()
                .map(WaitPakinItem::getAsnItemId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        if (asnItemIds.isEmpty()) {
            return;
        }
        if (!asnOrderItemService.update(new LambdaUpdateWrapper<WkOrderItem>()
                .in(WkOrderItem::getId, asnItemIds)
                .set(WkOrderItem::getBarcode, pakinBarcode)
                .set(WkOrderItem::getUpdateBy, loginUserId)
                .set(WkOrderItem::getUpdateTime, new Date()))) {
            throw new CoolException("通知单明细条码回写失败!!");
        }
    }
    /**
@@ -597,15 +623,44 @@
        if (StringUtils.isNotBlank(task.getTaskCode())) {
            rcsBusTaskNoticeService.notifyTaskStatus(task.getTaskCode(), task.getTaskStatus());
        }
        final Long taskIdForFinish = task.getId();
        if (TransactionSynchronizationManager.isSynchronizationActive()) {
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    taskService.runStockFinishAfterManualComplete(taskIdForFinish);
                }
            });
        }
        return task;
    }
    @Override
    public void runStockFinishAfterManualComplete(Long taskId) {
        if (taskId == null) {
            return;
        }
        try {
            Task t = taskService.getById(taskId);
            if (t == null) {
                return;
            }
            if (Objects.equals(t.getTaskStatus(), TaskStsType.COMPLETE_IN.id)) {
                taskService.complateInTask(Collections.singletonList(t));
            } else if (Objects.equals(t.getTaskStatus(), TaskStsType.COMPLETE_OUT.id)) {
                taskService.completeTask(Collections.singletonList(t));
            }
        } catch (Exception e) {
            log.warn("手动完结后立即库存收尾失败,将由定时任务重试,taskId={}:{}", taskId, e.getMessage());
        }
    }
    /**
     * 全版出库完结:扣除库位数量,将库位状态设为空
     * 全板出库完结:扣除库位数量,将库位状态设为空
     *
     * @param id 任务ID
     * @param loginUserId 登录用户ID
     * @param notifyRcsFromAdmin 管理后台全版出库完结接口为 true 时通知 RCS;定时/PDA 等为 false
     * @param notifyRcsFromAdmin 管理后台全板出库完结接口为 true 时通知 RCS;定时/PDA 等为 false
     * @return 任务对象
     */
    @Override
@@ -619,9 +674,9 @@
            throw new CoolException("任务不存在!!");
        }
        // 检查任务类型是否为全版出库
        // 检查任务类型是否为全板出库
        if (!task.getTaskType().equals(TaskType.TASK_TYPE_OUT.type)) {
            throw new CoolException("当前任务不是全版出库任务,无法执行此操作!!");
            throw new CoolException("当前任务不是全板出库任务,无法执行此操作!!");
        }
        // 检查任务状态:必须是199(WAVE_SEED)状态才能手动完结
@@ -1169,6 +1224,14 @@
                        .set(Loc::getUseStatus, LocStsType.LOC_STS_TYPE_F.type))) {
                    throw new CoolException("源库位状态修改失败!!");
                }
            } else if (task.getTaskType().equals(TaskType.TASK_TYPE_EMPITY_OUT.type)) {
                // 空板出库:建单时 D→R,取消恢复为空板 D
                if (!locService.update(new LambdaUpdateWrapper<Loc>()
                        .eq(Loc::getCode, task.getOrgLoc())
                        .eq(Loc::getUseStatus, LocStsType.LOC_STS_TYPE_R.type)
                        .set(Loc::getUseStatus, LocStsType.LOC_STS_TYPE_D.type))) {
                    throw new CoolException("空板出库源库位恢复空板失败!!");
                }
            }
            if (!Objects.isNull(task.getWarehType()) && task.getWarehType().equals(WarehType.WAREHOUSE_TYPE_AGV.val)) {
@@ -1212,7 +1275,7 @@
                            throw new CoolException("库位信息修改失败!!");
                        }
                        //出库
                        if (item.getWkType().equals(Short.parseShort(OrderWorkType.ORDER_WORK_TYPE_STOCK_OUT.type))) {
                        if (Objects.equals(item.getWkType(), OrderWorkType.ORDER_WORK_TYPE_STOCK_OUT.type)) {
                            //库存出库
                        } else if (task.getResource().equals(TaskResouceType.TASK_RESOUCE_WAVE_TYPE.val)) {
                            WaveItem waveItem = waveItemService.getById(item.getSource());
@@ -1234,7 +1297,7 @@
                                throw new CoolException("波次更新失败!!");
                            }
                        } else if (item.getWkType().equals(Short.parseShort(OrderWorkType.ORDER_WORK_TYPE_OTHER.type))) {
                        } else if (Objects.equals(item.getWkType(), OrderWorkType.ORDER_WORK_TYPE_OTHER.type)) {
                            //其它出库
                        } else {
@@ -1759,7 +1822,7 @@
            try {
                // 根据任务类型更新库位明细
                if (task.getTaskType().equals(TaskType.TASK_TYPE_OUT.type)) {
                    // 全版出库:不删除库位明细,等待PDA快速拣货确认时再删除
                    // 全板出库:不删除库位明细,等待PDA快速拣货确认时再删除
                    // subtractLocItem(loc); // 已移除,改为在completeFullOutStock中删除
                } else if (!TaskType.TASK_TYPE_PICK_AGAIN_OUT.type.equals(task.getTaskType())) {
                    // 部分出库(如盘点出库):根据TaskItem数量扣减库位明细;拣料出库在生成拣料入库单时扣减
@@ -1772,12 +1835,12 @@
        }
        //添加出入库记录信息
        Map<Short, List<TaskItem>> listMap = taskItems.stream().collect(Collectors.groupingBy(TaskItem::getWkType));
        Map<String, List<TaskItem>> listMap = taskItems.stream().collect(Collectors.groupingBy(TaskItem::getWkType));
        /***获取库存出库值,如果为空表示正常单据出库,非空表明是库存出库
         * 1. 库存出库没有单据信息,单据信息默认为空
         * 2. 单据库存需通过波次查询原始单据信息,将单据信息填入stock中
         * */
        List<TaskItem> list = listMap.get(Short.parseShort(OrderWorkType.ORDER_WORK_TYPE_STOCK_OUT.type));
        List<TaskItem> list = listMap.get(OrderWorkType.ORDER_WORK_TYPE_STOCK_OUT.type);
        if (Objects.isNull(list) || list.isEmpty()) {
            Map<Long, List<TaskItem>> maps = taskItems.stream().collect(Collectors.groupingBy(TaskItem::getSource));
            maps.keySet().forEach(key -> {
@@ -1828,7 +1891,7 @@
            // 拣料出库/盘点出库:在未生成拣料入库单之前保持 R.预约出库,否则下发任务时查不到该库位(只查 F+R)导致“库存不足”
            // 等 PDA 确认并生成拣料入库任务时,再在 pickOrCheckTask 中将目标库位改为 S.预约入库
        } else if (task.getTaskType().equals(TaskType.TASK_TYPE_OUT.type)) {
            // 全版出库:不更新库位状态为O,等待PDA快速拣货确认时再更新
            // 全板出库:不更新库位状态为O,等待PDA快速拣货确认时再更新
            // 库位状态保持原样(R.出库预约状态)
        } else {
            /**修改为库位状态为O.空库*/
@@ -1949,13 +2012,13 @@
            if (!asnOrderService.updateById(wkOrder)) {
                throw new CoolException("出库单更新失败!!");
            }
            stock.setWkType(Short.parseShort(wkOrder.getWkType()))
            stock.setWkType(wkOrder.getWkType())
                    .setType(OrderType.ORDER_OUT.type);
        } else if (!Objects.isNull(diffItem)) {
            stock.setWkType(Short.parseShort(OrderWorkType.ORDER_WORK_TYPE_STOCK_CHECK.type))
            stock.setWkType(OrderWorkType.ORDER_WORK_TYPE_STOCK_CHECK.type)
                    .setType(OrderType.ORDER_CHECK.type);
        } else {
            stock.setWkType(Short.parseShort(OrderWorkType.ORDER_WORK_TYPE_STOCK_OUT.type))
            stock.setWkType(OrderWorkType.ORDER_WORK_TYPE_STOCK_OUT.type)
                    .setMemo("库存出库,无单据信息!!")
                    .setType(OrderType.ORDER_OUT.type);
        }
@@ -2081,6 +2144,15 @@
                    log.error("========== RCS任务下发失败 ==========");
                    log.error("站点不存在!!任务编码:{},目标站点:{}", task.getTaskCode(), task.getTargSite());
                    continue;
                }
                // 出库下发前校验站点状态与出库能力
                if (task.getTaskType() >= TaskType.TASK_TYPE_OUT.type) {
                    if (!Integer.valueOf(1).equals(station.getStatus()) || !Integer.valueOf(1).equals(station.getOutAble())) {
                        log.error("========== RCS任务下发失败 ==========");
                        log.error("站点不可出库下发!!任务编码:{},目标站点:{},站点状态(status):{},能出(outAble):{}",
                                task.getTaskCode(), task.getTargSite(), station.getStatus(), station.getOutAble());
                        continue;
                    }
                }
            }
@@ -2386,7 +2458,7 @@
    /**
     * @author Ryan
     * @date 2025/5/20
     * @description: 扣减库存明细(全版出库:删除所有库位明细)
     * @description: 扣减库存明细(全板出库:删除所有库位明细)
     * @version 1.0
     */
    @Transactional(rollbackFor = Exception.class)
@@ -2549,6 +2621,10 @@
            WkOrder o = asnOrderService.getById(e.getKey());
            if (o != null) {
                Double newQty = QuantityUtils.roundToScale(QuantityUtils.add(o.getQty() != null ? o.getQty() : 0.0, e.getValue()));
                Double planQty = QuantityUtils.roundToScale(o.getAnfme() != null ? o.getAnfme() : 0.0);
                if (QuantityUtils.compare(newQty, planQty) > 0) {
                    newQty = planQty;
                }
                o.setQty(newQty);
                if (!asnOrderService.updateById(o)) {
                    throw new CoolException("入库单完成数量更新失败!!");
@@ -2559,6 +2635,10 @@
            WkOrderItem oi = asnOrderItemService.getById(e.getKey());
            if (oi != null) {
                Double newQty = QuantityUtils.roundToScale(QuantityUtils.add(oi.getQty() != null ? oi.getQty() : 0.0, e.getValue()));
                Double planQty = QuantityUtils.roundToScale(oi.getAnfme() != null ? oi.getAnfme() : 0.0);
                if (QuantityUtils.compare(newQty, planQty) > 0) {
                    newQty = planQty;
                }
                oi.setQty(newQty);
                if (!asnOrderItemService.updateById(oi)) {
                    throw new CoolException("入库单明细完成数量更新失败!!");
@@ -2691,7 +2771,7 @@
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public synchronized void saveStockItems(List<TaskItem> items, Task task, Long id, String code, Short wkType, String type, Long loginUserId) {
    public synchronized void saveStockItems(List<TaskItem> items, Task task, Long id, String code, String wkType, String type, Long loginUserId) {
        Stock stock = new Stock();
        String ruleCode = SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_STOCK_CODE, null);
        if (StringUtils.isBlank(ruleCode)) {
@@ -2800,9 +2880,18 @@
                    }
                }
            }
            // 入/出库均仅云仓来源单据参与上报(明细需带 platOrderCode 或 platWorkCode)
            boolean hasCloudSource = taskItems.stream().anyMatch(this::hasCloudOrderRef);
            if (!hasCloudSource) {
                log.info("入/出库结果上报待办跳过:无云仓来源单据,taskId={}", task.getId());
                return;
            }
            ObjectMapper om = new ObjectMapper();
            Date now = new Date();
            for (TaskItem item : taskItems) {
                if (!hasCloudOrderRef(item)) {
                    continue;
                }
                String orderNo = isInbound ? sourceToOrderNo.get(item.getSource()) : (item.getPlatOrderCode() != null ? item.getPlatOrderCode() : item.getPlatWorkCode());
                if (orderNo == null && isInbound) {
                    orderNo = item.getPlatOrderCode() != null ? item.getPlatOrderCode() : item.getPlatWorkCode();
@@ -2841,4 +2930,12 @@
            log.warn("入/出库结果上报待办失败,taskId={},isInbound={}:{}", task.getId(), isInbound, e.getMessage());
        }
    }
    private boolean hasCloudOrderRef(TaskItem item) {
        if (item == null) {
            return false;
        }
        return StringUtils.isNotBlank(item.getPlatOrderCode())
                || StringUtils.isNotBlank(item.getPlatWorkCode());
    }
}