chen.lin
20 小时以前 c67e3d0295858a61122354a15dec8835044bac0d
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java
@@ -18,6 +18,7 @@
import com.vincent.rsf.server.api.entity.params.WcsTaskParams;
import com.vincent.rsf.server.api.service.WcsService;
import com.vincent.rsf.server.common.constant.Constants;
import com.vincent.rsf.server.common.utils.QuantityUtils;
import com.vincent.rsf.server.manager.controller.params.LocToTaskParams;
import com.vincent.rsf.server.manager.controller.params.PakinItem;
import com.vincent.rsf.server.manager.enums.*;
@@ -860,6 +861,12 @@
            throw new CoolException("任务明细不存在!!");
        }
        if (TaskType.TASK_TYPE_PICK_IN.type.equals(task.getTaskType())) {
            // 拣料再入库:出库时已在 pickOrCheckTask 中扣减原库位(1100 -> 1089.899),
            // 入库完成时不再回写/累加库位明细,保持 1 条 1089.899,避免出现两条 1100
            // 仅更新库位状态、清理 LocItemWorking、任务状态及流水
        } else {
            // 盘点入库等:沿用原逻辑,从 LocItemWorking 回写并 saveBatch
        List<LocItem> items = new ArrayList<>();
        for (TaskItem taskItem : taskItems) {
            LocItem locItem = new LocItem();
@@ -873,9 +880,6 @@
            }
            if (task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_IN.type)) {
                locWorking.setAnfme(taskItem.getAnfme());
            } else if (task.getTaskType().equals(TaskType.TASK_TYPE_PICK_IN.type) && taskItem.getQty() != null && taskItem.getQty().compareTo(0.0) > 0) {
                // 拣料再入库:入库数量为本次拣料数量(taskItem.qty),保证与出库扣减一致
                locWorking.setAnfme(taskItem.getQty());
            }
            BeanUtils.copyProperties(locWorking, locItem);
            locItem.setWorkQty(0.0).setQty(0.0).setLocCode(loc.getCode()).setLocId(loc.getId()).setId(null).setUpdateBy(loginUserId).setUpdateTime(new Date());
@@ -885,8 +889,9 @@
            }
        }
        if (!locItemService.saveBatch(items)) {
            if (!items.isEmpty() && !locItemService.saveBatch(items)) {
//            throw new CoolException("作业库存回写失败!!");
            }
        }
        TaskItem taskItem = taskItems.stream().findFirst().get();
@@ -1290,7 +1295,7 @@
//        if (Objects.isNull(locInfo)) {
//            throw new CoolException("获取库位失败!!");
//        }
        //希日上报物有情况,不需要获取新库位
        //上报物有情况,不需要获取新库位
        task.setTargLoc(task.getOrgLoc())
                .setOrgSite(task.getTargSite());
@@ -1299,16 +1304,70 @@
        }
        //获取因当前任务出库的所有物料信息
        List<LocItemWorking> tempLocs = locItemWorkingService.list(new LambdaQueryWrapper<LocItemWorking>().eq(LocItemWorking::getTaskId, task.getId()));
        if (tempLocs.isEmpty()) {
            throw new CoolException("数据错误,作业中库存数据丢失!!");
        }
        List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, task.getId()));
        if (taskItems.isEmpty()) {
            throw new CoolException("数据错误:任务明细为空!!");
        }
        // 与查询一致:若无作业中库存但存在任务明细,用任务明细在内存中兜底,避免“能查到却无法确认”
        if (tempLocs.isEmpty()) {
            tempLocs = taskItems.stream().map(ti -> {
                LocItemWorking w = new LocItemWorking();
                w.setTaskId(task.getId());
                w.setFieldsIndex(ti.getFieldsIndex());
                w.setAnfme(ti.getAnfme());
                w.setMatnrId(ti.getMatnrId());
                w.setMaktx(ti.getMaktx());
                w.setMatnrCode(ti.getMatnrCode());
                w.setSpec(ti.getSpec());
                w.setBatch(ti.getBatch());
                w.setUnit(ti.getUnit());
                w.setModel(ti.getModel());
                return w;
            }).collect(Collectors.toList());
        }
        // 拣料入库:在生成拣料入库单时扣减原库位数量,不依赖出库完成时库位状态为R
        // 拣料入库:先算剩余数量并更新 taskItem.anfme,已拣数量 taskItem.qty = 原库位 - 剩余(保证 数量=100、已拣数量=1、库存明细=100)
        if (TaskType.TASK_TYPE_PICK_IN.type.equals(type)) {
            log.debug("[拣料入库] 开始处理 taskId={}, taskCode={}, orgLoc={}, tempLocs.size={}, taskItems.size={}",
                    task.getId(), task.getTaskCode(), task.getOrgLoc(), tempLocs.size(), taskItems.size());
            tempLocs.forEach(working -> {
                taskItems.forEach(taskItem -> {
                    if (Objects.equals(taskItem.getFieldsIndex(), working.getFieldsIndex())) {
                        // 已拣数量:优先用 taskItem.qty;为 0 时从出库单明细取 执行数(workQty) 或 订单数量(anfme),避免手动完结未填 qty 导致不扣减
                        Double pickedQty = taskItem.getQty() != null && QuantityUtils.isPositive(taskItem.getQty())
                                ? taskItem.getQty()
                                : 0.0;
                        log.debug("[拣料入库] taskItemId={}, fieldsIndex={}, working.anfme={}, taskItem.qty={}, taskItem.orderItemId={}, pickedQty(初)={}",
                                taskItem.getId(), taskItem.getFieldsIndex(), working.getAnfme(), taskItem.getQty(), taskItem.getOrderItemId(), pickedQty);
                        if (pickedQty <= 0 && taskItem.getOrderItemId() != null) {
                            WkOrderItem orderItem = asnOrderItemService.getById(taskItem.getOrderItemId());
                            log.debug("[拣料入库] 查出库单明细 orderItemId={}, orderItem={}, workQty={}, anfme={}",
                                    taskItem.getOrderItemId(), orderItem != null ? "存在" : "null",
                                    orderItem != null ? orderItem.getWorkQty() : null, orderItem != null ? orderItem.getAnfme() : null);
                            if (orderItem != null) {
                                if (orderItem.getWorkQty() != null && QuantityUtils.isPositive(orderItem.getWorkQty())) {
                                    pickedQty = orderItem.getWorkQty();
                                } else if (orderItem.getAnfme() != null && QuantityUtils.isPositive(orderItem.getAnfme())) {
                                    pickedQty = orderItem.getAnfme();
                                }
                            }
                        }
                        Double minQty = QuantityUtils.subtract(working.getAnfme(), pickedQty);
                        log.debug("[拣料入库] 计算后 pickedQty={}, minQty(剩余)={}, 将更新 taskItem.anfme={}, taskItem.qty={}",
                                pickedQty, minQty, minQty, pickedQty);
                        if (QuantityUtils.isNonNegative(minQty)) {
                            taskItem.setAnfme(minQty);
                            taskItem.setQty(pickedQty);
                            if (!taskItemService.updateById(taskItem)) {
                                throw new CoolException("任务明细修改失败!!");
                            }
                        } else {
                            log.warn("[拣料入库] minQty<0 未更新 taskItem, taskItemId={}", taskItem.getId());
                        }
                    }
                });
            });
            log.debug("[拣料入库] 即将扣减库位 locId={}, locCode={}", loc.getId(), loc.getCode());
            subtractLocItemByTaskItems(loc, taskItems, SystemAuthUtils.getLoginUserId());
        }
@@ -1317,19 +1376,19 @@
                if (Objects.equals(taskItem.getFieldsIndex(), working.getFieldsIndex())) {
                    Double minQty = taskItem.getAnfme();
                    if (!task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_IN.type)) {
                        // 计算剩余数量:从LocItemWorking中减去TaskItem的拣料数量
                        minQty = Math.round((working.getAnfme() - taskItem.getQty()) * 1000000) / 1000000.0;
                        // 计算剩余数量
                        minQty = QuantityUtils.subtract(working.getAnfme(), taskItem.getQty());
                    }
                    if (minQty.compareTo(0.0) >= 0) {
                    if (QuantityUtils.isNonNegative(minQty)) {
                        // 更新TaskItem的剩余数量
                        taskItem.setAnfme(minQty);
                        if (!taskItemService.updateById(taskItem)) {
                            throw new CoolException("任务明细修改失败!!");
                        }
                        // 更新LocItemWorking的剩余数量(非盘点入库时需要更新)
                        // 更新LocItemWorking的剩余数量(非盘点入库时需要更新);仅持久化记录才写库
                        if (!task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_IN.type)) {
                            working.setAnfme(minQty);
                            if (!locItemWorkingService.updateById(working)) {
                            if (working.getId() != null && !locItemWorkingService.updateById(working)) {
                                throw new CoolException("作业库存数量更新失败!!");
                            }
                        }
@@ -1384,9 +1443,9 @@
                    .setQty(0.0)
                    .setLocId(loc1.getId())
                    .setLocCode(loc1.getCode());
            // 拣料再入库:目标库位数量应为本次拣料数量(taskItem.qty),不是原库位剩余数量(taskItem.anfme)
            if (TaskType.TASK_TYPE_PICK_IN.type.equals(task.getTaskType()) && taskItem.getQty() != null && taskItem.getQty().compareTo(0.0) > 0) {
                itemWorking.setAnfme(taskItem.getQty());
            // 拣料再入库:目标库位数量应为回库的剩余数量(taskItem.anfme),即原库位减掉本次拣出后的数量(如 1000 出库 10 → 990)
            if (TaskType.TASK_TYPE_PICK_IN.type.equals(task.getTaskType()) && taskItem.getAnfme() != null && taskItem.getAnfme().compareTo(0.0) > 0) {
                itemWorking.setAnfme(taskItem.getAnfme());
            }
            workings.add(itemWorking);
        });
@@ -2066,18 +2125,37 @@
    @Transactional(rollbackFor = Exception.class)
    public void subtractLocItemByTaskItems(Loc loc, List<TaskItem> taskItems, Long loginUserId) {
        for (TaskItem taskItem : taskItems) {
            // 查询对应的库位明细
            LocItem locItem = locItemService.getOne(new LambdaQueryWrapper<LocItem>()
            LambdaQueryWrapper<LocItem> locItemWrapper = new LambdaQueryWrapper<LocItem>()
                    .eq(LocItem::getLocId, loc.getId())
                    .eq(LocItem::getMatnrId, taskItem.getMatnrId())
                    .eq(StringUtils.isNotBlank(taskItem.getBatch()), LocItem::getBatch, taskItem.getBatch())
                    .eq(StringUtils.isNotBlank(taskItem.getFieldsIndex()), LocItem::getFieldsIndex, taskItem.getFieldsIndex()));
                    .eq(LocItem::getMatnrId, taskItem.getMatnrId());
            if (StringUtils.isNotBlank(taskItem.getBatch())) {
                locItemWrapper.eq(LocItem::getBatch, taskItem.getBatch());
            } else {
                locItemWrapper.and(w -> w.isNull(LocItem::getBatch).or().eq(LocItem::getBatch, ""));
            }
            if (StringUtils.isNotBlank(taskItem.getFieldsIndex())) {
                locItemWrapper.eq(LocItem::getFieldsIndex, taskItem.getFieldsIndex());
            } else {
                locItemWrapper.and(w -> w.isNull(LocItem::getFieldsIndex).or().eq(LocItem::getFieldsIndex, ""));
            }
            LocItem locItem = locItemService.getOne(locItemWrapper);
            log.info("[拣料入库-扣减库位] taskItemId={}, locId={}, matnrId={}, batch={}, fieldsIndex={}, locItem={}, locItem.anfme={}, taskItem.qty={}, taskItem.anfme={}",
                    taskItem.getId(), loc.getId(), taskItem.getMatnrId(), taskItem.getBatch(), taskItem.getFieldsIndex(),
                    locItem != null ? "存在" : "null", locItem != null ? locItem.getAnfme() : null, taskItem.getQty(), taskItem.getAnfme());
            if (Objects.nonNull(locItem)) {
                // 计算扣减后的数量
                Double newAnfme = Math.round((locItem.getAnfme() - taskItem.getQty()) * 1000000) / 1000000.0;
                // 扣减量:优先用本次拣料数量 taskItem.getQty();若为 0 且 taskItem.anfme 已为剩余数量,则扣减 = 原库位 - 剩余(用 BigDecimal 避免 Double 精度问题)
                Double deductQty = QuantityUtils.isPositive(taskItem.getQty())
                        ? taskItem.getQty()
                        : (taskItem.getAnfme() != null && QuantityUtils.compare(taskItem.getAnfme(), locItem.getAnfme()) < 0
                                ? QuantityUtils.subtract(locItem.getAnfme(), taskItem.getAnfme())
                                : 0.0);
                Double newAnfme = QuantityUtils.subtract(locItem.getAnfme(), deductQty);
                log.info("[拣料入库-扣减库位] locItemId={}, deductQty={}, 原anfme={}, newAnfme={}, 操作={}",
                        locItem.getId(), deductQty, locItem.getAnfme(), newAnfme, QuantityUtils.isNonPositive(newAnfme) ? "删除" : "更新");
                
                if (newAnfme.compareTo(0.0) <= 0) {
                if (QuantityUtils.isNonPositive(newAnfme)) {
                    // 数量小于等于0,删除库位明细
                    locItemService.removeById(locItem.getId());
                } else {
@@ -2089,6 +2167,9 @@
                        throw new CoolException("库位明细数量扣减失败!!");
                    }
                }
            } else {
                log.warn("[拣料入库-扣减库位] 未查到库位明细 locId={}, matnrId={}, batch={}, fieldsIndex={},未扣减",
                        loc.getId(), taskItem.getMatnrId(), taskItem.getBatch(), taskItem.getFieldsIndex());
            }
        }
    }