chen.lin
昨天 98d88ac8caf7f0991d741079474c262f1e252927
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/PdaOutStockServiceImpl.java
@@ -5,6 +5,8 @@
import com.vincent.rsf.framework.common.R;
import com.vincent.rsf.framework.exception.CoolException;
import com.vincent.rsf.server.api.entity.dto.ContainerWaveDto;
import com.vincent.rsf.server.api.entity.dto.ContainerWaveItemDto;
import com.vincent.rsf.server.api.entity.dto.QuickPickOrderModuleDto;
import com.vincent.rsf.server.api.entity.params.ContainerWaveParam;
import com.vincent.rsf.server.api.entity.params.WavePickItemsParams;
import com.vincent.rsf.server.api.service.PdaOutStockService;
@@ -28,6 +30,7 @@
import com.vincent.rsf.server.system.service.impl.FieldsItemServiceImpl;
import com.vincent.rsf.server.system.service.impl.FieldsServiceImpl;
import com.vincent.rsf.server.system.utils.SerialRuleUtils;
import com.vincent.rsf.server.common.constant.Constants;
import com.vincent.rsf.server.system.utils.SystemAuthUtils;
import lombok.Synchronized;
import org.apache.commons.lang3.StringUtils;
@@ -43,6 +46,7 @@
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.Date;
@Service
public class PdaOutStockServiceImpl implements PdaOutStockService {
@@ -74,47 +78,135 @@
    @Autowired
    private ConfigServiceImpl configService;
    /**
     * 快速拣货查询:同一箱码可能有多条任务,仅 RCS 出库回调后变为 199 的才展示;该箱码下仍不是 199 的 PDA 不显示。
     * 返回:orders 按出库单分模块、list/taskItems 该箱码下 199 任务明细。
     */
    @Override
    public R getOutStockTaskItem(String barcode) {
        LambdaQueryWrapper<Task> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Task::getBarcode, barcode);
        Task task = taskService.getOne(lambdaQueryWrapper);
        if (null == task) {
            return R.error("未查询到相关任务");
        // 只查 199(WAVE_SEED)/AWAIT:已确认变成 200 的绝不能扫出来,明确排除 200 避免第二次扫到
        List<Task> tasks = taskService.list(new LambdaQueryWrapper<Task>()
                .eq(Task::getBarcode, barcode)
                .in(Task::getTaskStatus, Arrays.asList(TaskStsType.WAVE_SEED.id, TaskStsType.AWAIT.id))
                .ne(Task::getTaskStatus, TaskStsType.UPDATED_OUT.id)
                .orderByAsc(Task::getId));
        if (tasks == null || tasks.isEmpty()) {
            return R.error("未查询到待确认任务");
        }
        List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, task.getId()));
        if (null == taskItems || taskItems.size() <= 0) {
        List<Long> taskIds = tasks.stream().map(Task::getId).collect(Collectors.toList());
        List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().in(TaskItem::getTaskId, taskIds));
        if (taskItems == null || taskItems.isEmpty()) {
            return R.error("任务出错,未查询到相关任务明细");
        }
        return R.ok(taskItems);
        // 同一箱码下可能有多条(多个出库单),按出库单分组;仅返回尚未拣完的订单模块
        String nullKey = "__none__";
        Map<String, List<TaskItem>> byOrder = taskItems.stream()
                .collect(Collectors.groupingBy(ti -> ti.getOrderId() != null ? "o_" + ti.getOrderId() : (StringUtils.isNotBlank(ti.getSourceCode()) ? "s_" + ti.getSourceCode() : nullKey)));
        List<QuickPickOrderModuleDto> orders = new ArrayList<>();
        for (Map.Entry<String, List<TaskItem>> e : byOrder.entrySet()) {
            List<TaskItem> items = e.getValue();
            boolean allPicked = items.stream().allMatch(ti -> ti.getQty() != null && ti.getAnfme() != null && ti.getQty().compareTo(ti.getAnfme()) >= 0);
            if (allPicked) continue;
            TaskItem first = items.get(0);
            orders.add(new QuickPickOrderModuleDto()
                    .setOrderId(first.getOrderId())
                    .setOrderCode(StringUtils.isNotBlank(first.getSourceCode()) ? first.getSourceCode() : ("单号:" + (first.getOrderId() != null ? first.getOrderId() : "—")))
                    .setItems(items));
        }
        R r = orders.isEmpty() ? R.ok("全部拣货已完成") : R.ok();
        r.put("orders", orders);
        r.put("taskItems", taskItems);
        r.put("list", taskItems); // 同一箱码下多条明细,便于直接展示
        return r;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    @Synchronized
    public R saveOutTaskSts(String barcode) {
        LambdaQueryWrapper<Task> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Task::getBarcode, barcode);
        Task task = taskService.getOne(lambdaQueryWrapper);
        if (null == task) {
            throw new CoolException("未找到容器号对应任务");
        // 只统计当前「待确认」任务:出库单有3单但只下发了2个任务时,2个任务都拣完即可确认并生成拣料入库;有任务被取消则只处理剩余任务
        List<Task> tasks = taskService.list(new LambdaQueryWrapper<Task>()
                .eq(Task::getBarcode, barcode)
                .in(Task::getTaskStatus, Arrays.asList(TaskStsType.WAVE_SEED.id, TaskStsType.AWAIT.id))
                .orderByAsc(Task::getId));
        if (tasks == null || tasks.isEmpty()) {
            throw new CoolException("未找到料箱码对应任务或任务状态不是等待确认");
        }
        if (!task.getTaskStatus().equals(TaskStsType.WAVE_SEED.id)) {
            return R.error("任务状态不是等待确认");
        Long loginUserId = SystemAuthUtils.getLoginUserId();
        if (loginUserId == null) {
            loginUserId = 1L;
        }
        List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, task.getId()));
        Map<Long, List<TaskItem>> maps = taskItems.stream().collect(Collectors.groupingBy(TaskItem::getSource));
        maps.keySet().forEach(key -> {
            WkOrderItem orderItem = asnOrderItemService.getById(key);
            if (Objects.isNull(orderItem)) {
                throw new CoolException("单据明细不存在!!");
        try {
            Task first = tasks.get(0);
            if (first.getTaskType().equals(TaskType.TASK_TYPE_PICK_AGAIN_OUT.type)) {
                // 确认前该箱码下已有 200 的(例如第一次已确认的):本次只把当前 199 置为 200,不生成拣料入库,避免“第二次误确认”导致错误扣减和生成入库
                long already200 = taskService.count(new LambdaQueryWrapper<Task>()
                        .eq(Task::getBarcode, barcode)
                        .eq(Task::getTaskType, TaskType.TASK_TYPE_PICK_AGAIN_OUT.type)
                        .eq(Task::getTaskStatus, TaskStsType.UPDATED_OUT.id));
                // 确认即已确认:当前 199 任务全部置为 200,并回写已拣数量(qty);仅当本次确认前没有任何 200 且确认后全部 200 时才统一扣减并生成拣料入库
                for (Task task : tasks) {
                    task.setTaskStatus(TaskStsType.UPDATED_OUT.id)
                            .setUpdateBy(loginUserId)
                            .setUpdateTime(new Date());
                    if (!taskService.updateById(task)) {
                        return R.error("更新任务状态失败");
                    }
                    List<TaskItem> items = taskItemService.list(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, task.getId()));
                    for (TaskItem ti : items) {
                        if (ti.getQty() == null || ti.getQty().compareTo(0.0) <= 0) {
                            ti.setQty(ti.getAnfme() != null ? ti.getAnfme() : 0.0);
                            ti.setUpdateBy(loginUserId);
                            ti.setUpdateTime(new Date());
                            taskItemService.updateById(ti);
                        }
                    }
                }
                long not200 = taskService.count(new LambdaQueryWrapper<Task>()
                        .eq(Task::getBarcode, barcode)
                        .ne(Task::getTaskStatus, TaskStsType.UPDATED_OUT.id));
                if (not200 > 0) {
                    return R.ok("确认成功");
                }
                // 本次确认前该箱码下已有 200 的,不在此处生成拣料入库,由定时任务在“全部 200”时统一处理
                if (already200 > 0) {
                    return R.ok("确认成功;同箱已有过确认任务,扣减与拣料入库由系统在全部200后统一处理");
                }
                // 本次确认前没有任何 200,且确认后同箱码已全部 200:统一扣减、有余量才生成拣料入库单
                List<Task> all200 = taskService.list(new LambdaQueryWrapper<Task>()
                        .eq(Task::getBarcode, barcode)
                        .eq(Task::getTaskType, TaskType.TASK_TYPE_PICK_AGAIN_OUT.type)
                        .eq(Task::getTaskStatus, TaskStsType.UPDATED_OUT.id)
                        .orderByAsc(Task::getId));
                for (Task task : all200) {
                    taskService.pickOrCheckTask(task.getId(), "");
                }
                return R.ok("确认成功,已统一扣减并生成拣料入库任务(有余量时)");
            }
        });
        task.setTaskStatus(TaskStsType.COMPLETE_OUT.id);
        if (!taskService.updateById(task)) {
            return R.error("更新任务状态失败");
            if (first.getTaskType().equals(TaskType.TASK_TYPE_CHECK_OUT.type)) {
                for (Task task : tasks) {
                    taskService.pickOrCheckTask(task.getId(), Constants.TASK_TYPE_OUT_CHECK);
                }
                return R.ok("确认成功,已创建盘点入库任务");
            }
            if (first.getTaskType().equals(TaskType.TASK_TYPE_OUT.type)) {
                for (Task task : tasks) {
                    taskService.completeFullOutStock(task.getId(), loginUserId);
                }
                return R.ok("确认成功,全版出库已完成");
            }
            for (Task task : tasks) {
                task.setTaskStatus(TaskStsType.UPDATED_OUT.id)
                        .setUpdateBy(loginUserId)
                        .setUpdateTime(new Date());
                if (!taskService.updateById(task)) {
                    return R.error("更新任务状态失败");
                }
            }
            return R.ok("确认成功");
        } catch (Exception e) {
            throw new CoolException("快速拣货确认失败:" + e.getMessage());
        }
        return R.ok("确认成功");
    }
    @Override
@@ -131,31 +223,56 @@
        if (Cools.isEmpty(barcode)) {
            throw new CoolException("参数有误");
        }
        Task task = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getBarcode, barcode));
        Task task = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getBarcode, barcode)
                .orderByDesc(Task::getId)
                .last("limit 1"));
        if (null == task) {
            throw new CoolException("未找到容器号对应任务");
            throw new CoolException("未找到料箱码对应任务");
        }
        if (!task.getTaskStatus().equals(TaskStsType.WAVE_SEED.id)) {
            return R.error("任务状态不是揀料狀態");
        }
        List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, task.getId()));
        Set<Long> longSet = taskItems.stream().map(TaskItem::getSourceId).collect(Collectors.toSet());
        List<WaveOrderRela> waveOrderRelas = waveOrderRelaService.list(new LambdaQueryWrapper<WaveOrderRela>()
                .in(WaveOrderRela::getWaveId, longSet));
        if (Cools.isEmpty(waveOrderRelas)) {
        // 当前料箱对应库位下所有处于「预约出库/拣货中」的任务(含可追加的后续订单)
        String orgLoc = task.getOrgLoc();
        List<Integer> pickingStatuses = Arrays.asList(TaskStsType.GENERATE_OUT.id, TaskStsType.WAVE_SEED.id);
        List<Task> sameLocTasks = taskService.list(new LambdaQueryWrapper<Task>()
                .eq(Task::getOrgLoc, orgLoc)
                .in(Task::getTaskStatus, pickingStatuses));
        Set<Long> waveIds = new java.util.HashSet<>();
        Set<String> matnrCodes = new java.util.HashSet<>();
        for (Task t : sameLocTasks) {
            List<TaskItem> items = taskItemService.list(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, t.getId()));
            for (TaskItem ti : items) {
                if (ti.getSourceId() != null) waveIds.add(ti.getSourceId());
                if (StringUtils.isNotBlank(ti.getMatnrCode())) matnrCodes.add(ti.getMatnrCode());
            }
        }
        if (waveIds.isEmpty()) {
            throw new CoolException("波次对应关联单未找到");
        }
        List<WaveOrderRela> waveOrderRelas = waveOrderRelaService.list(new LambdaQueryWrapper<WaveOrderRela>()
                .in(WaveOrderRela::getWaveId, waveIds));
        Set<Long> orderIds = waveOrderRelas.stream().map(WaveOrderRela::getOrderId).collect(Collectors.toSet());
        List<WkOrder> wkOrders = asnOrderService.listByIds(orderIds);
        if (wkOrders.isEmpty()) {
            throw new CoolException("单据不存在!!");
        }
        Set<String> codes = taskItems.stream().map(TaskItem::getMatnrCode).collect(Collectors.toSet());
        // 按订单创建时间排序,先创建的为主订单,后续为可追加
        wkOrders.sort(Comparator.comparing(WkOrder::getCreateTime, Comparator.nullsLast(Comparator.naturalOrder())));
        Set<String> codes = matnrCodes.isEmpty() ? taskItemService.list(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, task.getId()))
                .stream().map(TaskItem::getMatnrCode).filter(StringUtils::isNotBlank).collect(Collectors.toSet()) : matnrCodes;
        List<WkOrderItem> orderItems = asnOrderItemService.list(new LambdaQueryWrapper<WkOrderItem>()
                .in(WkOrderItem::getMatnrCode, codes)
                .in(WkOrderItem::getOrderId, orderIds));
        return R.ok("查询成功").add(orderItems);
        List<ContainerWaveItemDto> result = new ArrayList<>();
        Long firstOrderId = wkOrders.isEmpty() ? null : wkOrders.get(0).getId();
        for (WkOrderItem item : orderItems) {
            boolean appendable = firstOrderId != null && !firstOrderId.equals(item.getOrderId());
            result.add(new ContainerWaveItemDto().setOrderItem(item).setAppendable(appendable));
        }
        R r = R.ok("查询成功");
        r.put("list", result);
        return r;
//        ArrayList<ContainerWaveDto> containerWaveDtos = new ArrayList<>();
////        List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, task.getId()));
@@ -164,7 +281,7 @@
//            containerWaveDto.setTaskItem(taskItem);
//            Wave wave = waveService.getById(taskItem.getSourceId());
//            if (null == wave) {
//                throw new CoolException("未找到容器号对应波次");
//                throw new CoolException("未找到料箱码对应波次");
//            }
//            List<WaveOrderRela> waveOrderRelas = waveOrderRelaService.list(new LambdaQueryWrapper<WaveOrderRela>()
//                    .eq(WaveOrderRela::getWaveId, wave.getId()));
@@ -201,41 +318,58 @@
        if (Objects.isNull(param)) {
            return R.error("参数不能为空!!");
        }
        if (Objects.isNull(param.get("fieldsIndex"))) {
            return R.error("票号不能为空!!");
        }
        // 票号暂不使用,注释校验
        // if (Objects.isNull(param.get("fieldsIndex"))) {
        //     return R.error("票号不能为空!!");
        // }
        if (Objects.isNull(param.get("barcode"))) {
            return R.error("容器号不能为空!!");
            return R.error("料箱码不能为空!!");
        }
        if (Objects.isNull(param.get("orderId"))) {
            return R.error("订单ID不能为空!!");
        }
        Task task = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getBarcode, param.get("barcode").toString()));
        Task task = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getBarcode, param.get("barcode").toString())
                .orderByDesc(Task::getId)
                .last("limit 1"));
        if (Objects.isNull(task)) {
            throw new CoolException("数据错误,任务档已不存在!!");
        }
        FieldsItem fieldsItem = fieldsItemService.getOne(new LambdaQueryWrapper<FieldsItem>()
                .eq(FieldsItem::getValue, param.get("fieldsIndex").toString())
                .last("limit 1"));
        if (Objects.isNull(fieldsItem)) {
            return R.error("数据错误,票号不存在!!");
        }
        TaskItem taskItem = taskItemService.getOne(new LambdaQueryWrapper<TaskItem>()
        // 票号暂不使用,按任务取第一条明细
        // FieldsItem fieldsItem = fieldsItemService.getOne(new LambdaQueryWrapper<FieldsItem>()
        //         .eq(FieldsItem::getValue, param.get("fieldsIndex").toString())
        //         .last("limit 1"));
        // if (Objects.isNull(fieldsItem)) {
        //     return R.error("数据错误,票号不存在!!");
        // }
        TaskItem taskItem = null;
        FieldsItem fieldsItem = null;
        if (param.get("fieldsIndex") != null && StringUtils.isNotBlank(param.get("fieldsIndex").toString())) {
            fieldsItem = fieldsItemService.getOne(new LambdaQueryWrapper<FieldsItem>()
                    .eq(FieldsItem::getValue, param.get("fieldsIndex").toString())
                    .last("limit 1"));
            if (fieldsItem != null) {
                taskItem = taskItemService.getOne(new LambdaQueryWrapper<TaskItem>()
                        .eq(TaskItem::getFieldsIndex, fieldsItem.getUuid())
                .eq(TaskItem::getTaskId, task.getId()));
                        .eq(TaskItem::getTaskId, task.getId()));
            }
        }
        if (taskItem == null) {
            taskItem = taskItemService.getOne(new LambdaQueryWrapper<TaskItem>()
                    .eq(TaskItem::getTaskId, task.getId())
                    .last("limit 1"));
        }
        if (Objects.isNull(taskItem)) {
            return R.error("数据错误,任务档明细不存在!!");
        }
//        Long orderId = Long.valueOf(param.get("orderId").toString());
//        List<WkOrderItem> orderItems = asnOrderItemService.list(new LambdaQueryWrapper<WkOrderItem>().eq(WkOrderItem::getOrderId, orderId));
//        if (orderItems.isEmpty()) {
//            return R.error("数据错误,订单数据不存在!!");
//        }
        //根据索引获取动态字段Value值
        Map<String, String> fields = new HashMap<>();
        Fields fields1 = fieldsService.getById(fieldsItem.getFieldsId());
        fields.put(fields1.getFields(), fieldsItem.getValue());
        taskItem.setExtendFields(fields);
        // 票号暂不使用:仅当有 fieldsItem 时设置 extendFields
        if (fieldsItem != null) {
            Fields fields1 = fieldsService.getById(fieldsItem.getFieldsId());
            if (fields1 != null) {
                Map<String, String> fields = new HashMap<>();
                fields.put(fields1.getFields(), fieldsItem.getValue());
                taskItem.setExtendFields(fields);
            }
        }
        return R.ok().add(taskItem);
    }
@@ -250,7 +384,7 @@
    @Transactional(rollbackFor = Exception.class)
    public synchronized R wavePickItems(WavePickItemsParams params) {
        if (Objects.isNull(params.getBarcode())) {
            return R.error("托盘码不能为空!!");
            return R.error("料箱码不能为空!!");
        }
        if (Objects.isNull(params.getOrderId())) {
            return R.error("订单ID不能为空!!");
@@ -258,9 +392,11 @@
        if (Objects.isNull(params.getTaskItems()) || params.getTaskItems().isEmpty()) {
            return R.error("拣货明细不能为空!");
        }
        Task task = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getBarcode, params.getBarcode()));
        Task task = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getBarcode, params.getBarcode())
                .orderByDesc(Task::getId)
                .last("limit 1"));
        if (null == task) {
            return R.error("未找到托盘对应的任务");
            return R.error("未找到料箱对应的任务");
        }
        if (!task.getTaskStatus().equals(TaskStsType.WAVE_SEED.id)) {
            return R.error("任务状态不是揀料狀態");
@@ -271,109 +407,63 @@
        }
        List<TaskItem> taskItems = params.getTaskItems();
        Map<String, List<TaskItem>> listMap = taskItems.stream().collect(Collectors.groupingBy(TaskItem::getMatnrCode));
        // 拣货完成仅扣减库位数量并累加 TaskItem.qty,不更新出库单/订单;待托盘全部拣完在 saveWavePick 再按顺序更新库存并校验
        Config config = configService.getOne(new LambdaQueryWrapper<Config>().eq(Config::getFlag, GlobalConfigCode.ALLOW_OVER_CHANGE));
        listMap.keySet().forEach(code -> {
            List<TaskItem> items = listMap.get(code);
            //一张出库单,相同的品种不会出现两次
            WkOrderItem orderItem = asnOrderItemService.getOne(new LambdaQueryWrapper<WkOrderItem>()
                    .eq(WkOrderItem::getMatnrCode, code)
                    .eq(WkOrderItem::getOrderId, order.getId()));
            if (Objects.isNull(orderItem)) {
                throw new CoolException("数据错误,拣料不在单据需求中!!");
            }
            //taskItems为拣货明细,作参数上报
            Double summed = items.stream().mapToDouble(TaskItem::getAnfme).sum();
            //加上历史拣料数量
            Double pickQty = Math.round((orderItem.getQty() + summed) * 1000000) / 1000000.0;
            Config config = configService.getOne(new LambdaQueryWrapper<Config>().eq(Config::getFlag, GlobalConfigCode.ALLOW_OVER_CHANGE));
            //判断是否允许超收,不允许超收添加拒收判断
            if (!Objects.isNull(config)) {
                if (!Boolean.parseBoolean(config.getVal())) {
                    if (pickQty.compareTo(orderItem.getAnfme()) > 0.0) {
                        throw new CoolException("播种数量不能超出订单需求数量");
                    }
            Double summed = items.stream().mapToDouble(ti -> ti.getAnfme() != null ? ti.getAnfme() : 0.0).sum();
            Double pickQty = Math.round((orderItem.getQty() != null ? orderItem.getQty() : 0.0) + summed) * 1000000.0 / 1000000.0;
            if (!Objects.isNull(config) && !Boolean.parseBoolean(config.getVal())) {
                if (pickQty.compareTo(orderItem.getAnfme()) > 0.0) {
                    throw new CoolException("播种数量不能超出订单需求数量");
                }
            }
            orderItem.setQty(pickQty);
            if (!asnOrderItemService.updateById(orderItem)) {
                throw new CoolException("出库单明细更新失败!!");
            }
            Stock stock = new Stock();
            String ruleCode = SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_STOCK_CODE, null);
            if (StringUtils.isBlank(ruleCode)) {
                throw new CoolException("当前业务:" + SerialRuleCode.SYS_STOCK_CODE + ",编码规则不存在!!");
            }
            Double sum = taskItems.stream().mapToDouble(TaskItem::getAnfme).sum();
            stock.setCode(ruleCode)
                    .setUpdateBy(SystemAuthUtils.getLoginUserId())
                    .setBarcode(task.getBarcode())
                    .setLocCode(task.getOrgLoc())
                    .setType(order.getType())
                    .setWkType(Short.parseShort(order.getWkType()))
                    .setSourceId(orderItem.getOrderId())
                    .setSourceCode(orderItem.getOrderCode())
                    .setUpdateTime(new Date())
                    .setAnfme(sum);
            if (!stockService.save(stock)) {
                throw new CoolException("出入库历史保存失败!!");
            }
           List<StockItem> stockItems = new ArrayList<>();
            items.forEach(taskItem -> {
                TaskItem item = taskItemService.getById(taskItem.getId());
                //判断是否允许超收,不允许超收添加拒收判断
                if (!Objects.isNull(config)) {
                    LocItemWorking serviceOne = locItemWorkingService.getOne(new LambdaQueryWrapper<LocItemWorking>().eq(LocItemWorking::getFieldsIndex, item.getFieldsIndex()));
                    if (Objects.isNull(serviceOne)) {
                        throw new CoolException("缓存数据丢失!!");
                if (Objects.isNull(item)) {
                    throw new CoolException("任务明细不存在!!");
                }
                if (!Objects.isNull(config) && !Boolean.parseBoolean(config.getVal())) {
                    Double v = Math.round(((item.getQty() != null ? item.getQty() : 0.0) + (taskItem.getAnfme() != null ? taskItem.getAnfme() : 0.0)) * 1000000.0) / 1000000.0;
                    if (item.getAnfme() != null && item.getAnfme().compareTo(v) < 0.0) {
                        throw new CoolException("当前物料已超出可拣范围,请核对后再操作!!");
                    }
                    //不管是否允许超收,都需判断是否超出库存范围
                    if (taskItem.getAnfme().compareTo(serviceOne.getAnfme()) > 0) {
                        throw new CoolException("拣货数量超出当前票号库存数量!!");
                    }
                    if (!Boolean.parseBoolean(config.getVal())) {
                        Double v = Math.round((item.getQty() + taskItem.getAnfme()) * 1000000) / 1000000.0;
                        if (item.getAnfme().compareTo(v) < 0.0) {
                            throw new CoolException("前当物料已超出可拣范围,请核对后再操作!!");
                }
                Double picQty = Math.round(((item.getQty() != null ? item.getQty() : 0.0) + (taskItem.getAnfme() != null ? taskItem.getAnfme() : 0.0)) * 1000000.0) / 1000000.0;
                item.setQty(picQty).setOrderId(order.getId()).setOrderItemId(orderItem.getId());
                if (!taskItemService.updateById(item)) {
                    throw new CoolException("拣货数量更新失败!!");
                }
                if (StringUtils.isNotBlank(task.getOrgLoc())) {
                    LocItem locItem = locItemService.getOne(new LambdaQueryWrapper<LocItem>()
                            .eq(LocItem::getLocCode, task.getOrgLoc())
                            .eq(LocItem::getMatnrId, item.getMatnrId())
                            .eq(StringUtils.isNotBlank(item.getBatch()), LocItem::getBatch, item.getBatch())
                            .eq(StringUtils.isNotBlank(item.getFieldsIndex()), LocItem::getFieldsIndex, item.getFieldsIndex()));
                    if (Objects.nonNull(locItem)) {
                        Double pickAmt = taskItem.getAnfme() != null ? taskItem.getAnfme() : 0.0;
                        Double newAnfme = Math.round((locItem.getAnfme() - pickAmt) * 1000000.0) / 1000000.0;
                        if (newAnfme.compareTo(0.0) <= 0) {
                            locItemService.removeById(locItem.getId());
                        } else {
                            locItem.setAnfme(newAnfme)
                                    .setUpdateBy(SystemAuthUtils.getLoginUserId())
                                    .setUpdateTime(new Date());
                            if (!locItemService.updateById(locItem)) {
                                throw new CoolException("库位明细数量扣减失败!!");
                            }
                        }
                    }
                }
                Double picQty = Math.round((item.getQty() + taskItem.getAnfme()) * 1000000) / 1000000.0;
                item.setQty(picQty).setOrderId(order.getId()).setOrderItemId(orderItem.getId());
                if (!taskItemService.updateById(item)) {
                    throw new CoolException("状态完成失败!!");
                }
                StockItem stockItem = new StockItem();
                BeanUtils.copyProperties(item, stockItem);
                //taskItem为上报数据
                stockItem.setStockId(stock.getId()).setAnfme(taskItem.getAnfme()).setStockCode(stock.getCode()).setSourceItemId(orderItem.getId());
                stockItems.add(stockItem);
            });
            if (!stockItemService.saveBatch(stockItems)) {
                throw new CoolException("出入库历史明细保存失败!!");
            }
        });
        List<WkOrderItem> orderItems = asnOrderItemService.list(new LambdaQueryWrapper<WkOrderItem>().eq(WkOrderItem::getOrderId, params.getOrderId()));
        Double total = orderItems.stream().mapToDouble(WkOrderItem::getQty).sum();
        Double wkQty = orderItems.stream().mapToDouble(WkOrderItem::getWorkQty).sum();
        double v = order.getWorkQty().compareTo(wkQty) < 0 ? 0.0 : Math.round((total - wkQty) * 1000000) / 1000000.0;
        order.setQty(total).setWorkQty(v);
        if (!asnOrderService.updateById(order)) {
            throw new CoolException("订单数量更新失败!!");
        }
//        //检查单据是否完成
//        if (order.getAnfme().compareTo(order.getQty()) == 0) {
//            order.setExceStatus(AsnExceStatus.OUT_STOCK_STATUS_TASK_DONE.val);
//            if (!asnOrderService.updateById(order)) {
//                throw new CoolException("出库单更新状态失败");
//            }
//        }
        return R.ok();
    }
@@ -393,7 +483,7 @@
                .in(Task::getTaskType, integers)
                .eq(Task::getBarcode, params.get("barcode")), false);
        if (Objects.isNull(task)) {
            return R.error("托盘所在任务不存在!!");
            return R.error("料箱所在任务不存在!!");
        }
        List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, task.getId()));
        taskItems.forEach(taskItem -> {
@@ -418,6 +508,9 @@
            return R.error("参数不能为空!!");
        }
        for (TaskItem item : items) {
            // 票号暂不使用,跳过修改出库任务档明细票号逻辑
            continue;
            /*
            if (Objects.isNull(item.getCrushNo())) {
                continue;
            }
@@ -426,7 +519,7 @@
                Map<String, String> fields = FieldsUtils.getFields(byId.getFieldsIndex());
                byId.setExtendFields(fields);
            }
            if (byId.getExtendFields().get("crushNo").equals(item.getCrushNo())) {
            if (byId.getExtendFields() != null && byId.getExtendFields().get("crushNo") != null && byId.getExtendFields().get("crushNo").equals(item.getCrushNo())) {
                continue;
            }
            FieldsItem fieldsItem = fieldsItemService.getOne(new LambdaQueryWrapper<FieldsItem>()
@@ -441,13 +534,15 @@
               throw new CoolException("任务明细修改失败");
            }
            LocItemWorking oldOne = locItemWorkingService.getOne(new LambdaQueryWrapper<LocItemWorking>()
                    .eq(LocItemWorking::getTaskId, byId.getTaskId())
                    .eq(LocItemWorking::getMatnrCode, byId.getMatnrCode())
                    .eq(LocItemWorking::getFieldsIndex, byId.getFieldsIndex()));
            if (Objects.isNull(oldOne)) {
                throw new CoolException("明细不存在或已出库!!");
            }
            LocItemWorking one = locItemWorkingService.getOne(new LambdaQueryWrapper<LocItemWorking>()
                            .eq(LocItemWorking::getMatnrCode, byId.getMatnrCode())
                    .eq(LocItemWorking::getTaskId, byId.getTaskId())
                    .eq(LocItemWorking::getMatnrCode, byId.getMatnrCode())
                    .eq(LocItemWorking::getFieldsIndex, uuid));
            if (Objects.isNull(one)) {
                throw new CoolException("明细不存在或已出库!!");
@@ -458,7 +553,7 @@
            //更新库位信息
            locItemWorkingService.updateById(oldOne);
            locItemWorkingService.updateById(one);
            */
        }
        return R.ok();
    }
@@ -482,31 +577,82 @@
            return R.error("数据错误!!");
        }
        Task task = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getBarcode, containerWaveParam.getContainer()));
        Task task = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getBarcode, containerWaveParam.getContainer())
                .orderByDesc(Task::getId)
                .last("limit 1"));
        if (null == task) {
            return R.error("未找到托盘对应的任务");
            return R.error("未找到料箱对应的任务");
        }
        if (!task.getTaskStatus().equals(TaskStsType.WAVE_SEED.id)) {
            return R.error("任务状态不是待揀狀態");
        }
        Config config = configService.getOne(new LambdaQueryWrapper<Config>().eq(Config::getFlag, GlobalConfigCode.ALLOW_OVER_CHANGE));
        //判断是否允许超收,不允许超收添加拒收判断
        if (!Objects.isNull(config)) {
            if (!Boolean.parseBoolean(config.getVal())) {
                List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, task.getId()));
                taskItems.forEach(taskItem -> {
                    if ((taskItem.getQty().compareTo(taskItem.getAnfme()) < 0)) {
                        throw new CoolException("有单据物料未拣,请拣完后再确认!!");
                    }
                });
        List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, task.getId()));
        // 必须当前托盘关联出库单全部拣货完成才允许确认
        for (TaskItem ti : taskItems) {
            Double q = ti.getQty() != null ? ti.getQty() : 0.0;
            Double a = ti.getAnfme() != null ? ti.getAnfme() : 0.0;
            if (q.compareTo(a) < 0) {
                throw new CoolException("有单据物料未拣完,请完成该托盘下所有订单拣货后再确认!!");
            }
        }
        // 按顺序更新出库单明细、订单及库存流水(与 wavePickItems 原逻辑一致,在全部拣完后统一执行)
        Map<Long, List<TaskItem>> byOrder = taskItems.stream()
                .filter(ti -> ti.getOrderId() != null)
                .collect(Collectors.groupingBy(TaskItem::getOrderId));
        List<Long> orderIds = new ArrayList<>(byOrder.keySet());
        orderIds.sort(Long::compareTo);
        for (Long orderId : orderIds) {
            WkOrder order = asnOrderService.getById(orderId);
            if (order == null) continue;
            List<TaskItem> items = byOrder.get(orderId);
            Map<String, List<TaskItem>> byMatnr = items.stream().collect(Collectors.groupingBy(TaskItem::getMatnrCode));
            for (String code : byMatnr.keySet()) {
                List<TaskItem> matItems = byMatnr.get(code);
                WkOrderItem orderItem = asnOrderItemService.getOne(new LambdaQueryWrapper<WkOrderItem>()
                        .eq(WkOrderItem::getMatnrCode, code)
                        .eq(WkOrderItem::getOrderId, orderId));
                if (orderItem == null) continue;
                Double summed = matItems.stream().mapToDouble(t -> t.getQty() != null ? t.getQty() : 0.0).sum();
                orderItem.setQty(summed);
                asnOrderItemService.updateById(orderItem);
                String ruleCode = SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_STOCK_CODE, null);
                if (StringUtils.isBlank(ruleCode)) continue;
                Stock stock = new Stock();
                stock.setCode(ruleCode)
                        .setUpdateBy(loginUserId)
                        .setBarcode(task.getBarcode())
                        .setLocCode(task.getOrgLoc())
                        .setType(order.getType())
                        .setWkType(Short.parseShort(order.getWkType()))
                        .setSourceId(orderItem.getOrderId())
                        .setSourceCode(orderItem.getOrderCode())
                        .setUpdateTime(new Date())
                        .setAnfme(summed);
                if (!stockService.save(stock)) continue;
                List<StockItem> stockItems = new ArrayList<>();
                for (TaskItem ti : matItems) {
                    StockItem si = new StockItem();
                    BeanUtils.copyProperties(ti, si);
                    si.setStockId(stock.getId()).setAnfme(ti.getQty()).setStockCode(stock.getCode()).setSourceItemId(orderItem.getId());
                    stockItems.add(si);
                }
                stockItemService.saveBatch(stockItems);
            }
            List<WkOrderItem> ois = asnOrderItemService.list(new LambdaQueryWrapper<WkOrderItem>().eq(WkOrderItem::getOrderId, orderId));
            Double total = ois.stream().mapToDouble(oi -> oi.getQty() != null ? oi.getQty() : 0.0).sum();
            Double wkQty = ois.stream().mapToDouble(oi -> oi.getWorkQty() != null ? oi.getWorkQty() : 0.0).sum();
            double v = (order.getWorkQty() != null && order.getWorkQty().compareTo(wkQty) < 0) ? 0.0 : Math.round((total - wkQty) * 1000000.0) / 1000000.0;
            order.setQty(total).setWorkQty(v);
            asnOrderService.updateById(order);
        }
        try {
            if (task.getTaskType().equals(TaskType.TASK_TYPE_PICK_AGAIN_OUT.type) || task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_OUT.type)) {
            if (task.getTaskType().equals(TaskType.TASK_TYPE_PICK_AGAIN_OUT.type)) {
                taskService.pickOrCheckTask(task.getId(), "");
            } else if (task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_OUT.type)) {
                taskService.pickOrCheckTask(task.getId(), Constants.TASK_TYPE_OUT_CHECK);
            } else {
                task.setTaskStatus(TaskStsType.UPDATED_OUT.id);
                if (!taskService.updateById(task)) {
@@ -514,7 +660,7 @@
                }
            }
        } catch (Exception e) {
            throw new CoolException("分拣失败");
            throw new CoolException("分拣失败:" + e.getMessage());
        }
        return R.ok();
    }