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)状态才能手动完结
@@ -1767,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数量扣减库位明细;拣料出库在生成拣料入库单时扣减
@@ -1836,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.空库*/
@@ -2089,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;
                    }
                }
            }
@@ -2394,7 +2458,7 @@
    /**
     * @author Ryan
     * @date 2025/5/20
     * @description: 扣减库存明细(全版出库:删除所有库位明细)
     * @description: 扣减库存明细(全板出库:删除所有库位明细)
     * @version 1.0
     */
    @Transactional(rollbackFor = Exception.class)
@@ -2557,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("入库单完成数量更新失败!!");
@@ -2567,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("入库单明细完成数量更新失败!!");
@@ -2808,19 +2880,16 @@
                    }
                }
            }
            // 出库仅云仓来源单据参与上报
            if (!isInbound) {
                boolean hasCloudSource = taskItems.stream().anyMatch(this::hasCloudOrderRef);
                if (!hasCloudSource) {
//                    log.info("入/出库结果上报待办跳过:无云仓来源单据,taskId={}", task.getId());
                    log.info("入/出库结果上报待办跳过:手动创建出库单据不通知云仓,taskId={}", task.getId());
                    return;
                }
            // 入/出库均仅云仓来源单据参与上报(明细需带 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 (!isInbound && !hasCloudOrderRef(item)) {
                if (!hasCloudOrderRef(item)) {
                    continue;
                }
                String orderNo = isInbound ? sourceToOrderNo.get(item.getSource()) : (item.getPlatOrderCode() != null ? item.getPlatOrderCode() : item.getPlatWorkCode());