4 小时以前 6d910029b6c81db0a2b66caa66952781397b153a
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/stocktaking/task/MesWmStockTakingTaskServiceImpl.java
@@ -2,17 +2,29 @@
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.mes.controller.admin.wm.stocktaking.task.vo.MesWmStockTakingTaskPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.stocktaking.task.vo.MesWmStockTakingTaskSaveReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.stocktaking.task.vo.MesWmStockTakingTaskScanReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.stocktaking.task.vo.result.MesWmStockTakingTaskResultSaveReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.pallet.MesProPalletDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.stocktaking.task.MesWmStockTakingTaskDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.stocktaking.task.MesWmStockTakingTaskLineDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.stocktaking.task.MesWmStockTakingTaskResultDO;
import cn.iocoder.yudao.module.mes.dal.mysql.pro.bagcode.MesProBagCodeMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.pro.pallet.MesProPalletMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.stocktaking.task.MesWmStockTakingTaskLineMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.stocktaking.task.MesWmStockTakingTaskMapper;
import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmStockTakingTaskStatusEnum;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum;
import cn.iocoder.yudao.module.mes.service.pro.batch.MesProBatchService;
import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService;
import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService;
import cn.iocoder.yudao.module.mes.service.wm.stocktaking.plan.MesWmStockTakingPlanService;
import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService;
@@ -56,6 +68,17 @@
    @Resource
    private MesWmTransactionService wmTransactionService;
    @Resource
    private MesWmStockTakingTaskLineMapper stockTakingTaskLineMapper;
    @Resource
    private MesWmBatchService mesWmBatchService;
    @Resource
    private MesProBatchService proBatchService;
    @Resource
    private MesProBagCodeMapper bagCodeMapper;
    @Resource
    private MesProPalletMapper palletMapper;
    @Resource
    private AdminUserApi adminUserApi;
@@ -231,6 +254,69 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long scanStockTakingTask(MesWmStockTakingTaskScanReqVO scanReqVO) {
        // 1. 校验任务存在且处于盘点中状态
        validateStockTakingTaskExistsAndApproving(scanReqVO.getTaskId());
        // 2. 解析追溯码定位仓库批次(支持批次号/袋码/托盘码,走生产批次桥接)
        MesWmBatchDO wmBatch = resolveWmBatchByScanCode(scanReqVO.getScanCode());
        if (wmBatch == null) {
            throw exception(WM_STOCK_TAKING_TASK_SCAN_BATCH_NOT_FOUND);
        }
        // 3. 在任务范围内定位任务行
        MesWmStockTakingTaskLineDO line = stockTakingTaskLineMapper
                .selectByTaskIdAndBatchId(scanReqVO.getTaskId(), wmBatch.getId());
        if (line == null) {
            throw exception(WM_STOCK_TAKING_TASK_SCAN_BATCH_NOT_IN_TASK);
        }
        // 4. 写入盘点结果(复用 createStockTakingTaskResult:含重复盘点校验,联动更新任务行盘点数量与盈亏状态)
        MesWmStockTakingTaskResultSaveReqVO resultReqVO = new MesWmStockTakingTaskResultSaveReqVO()
                .setTaskId(line.getTaskId()).setLineId(line.getId())
                .setMaterialStockId(line.getMaterialStockId())
                .setItemId(line.getItemId()).setBatchId(line.getBatchId()).setBatchCode(line.getBatchCode())
                .setWarehouseId(line.getWarehouseId()).setLocationId(line.getLocationId()).setAreaId(line.getAreaId())
                .setTakingQuantity(scanReqVO.getTakingQuantity())
                .setRemark(scanReqVO.getRemark());
        return stockTakingTaskResultService.createStockTakingTaskResult(resultReqVO);
    }
    /**
     * 解析追溯码定位仓库批次:依次匹配批次号、袋码、托盘码,生产批次经桥接返回仓库批次
     */
    private MesWmBatchDO resolveWmBatchByScanCode(String scanCode) {
        if (StrUtil.isBlank(scanCode)) {
            return null;
        }
        // 1. 直接命中仓库批次号
        MesWmBatchDO wmBatch = mesWmBatchService.getBatchByCode(scanCode);
        if (wmBatch != null) {
            return wmBatch;
        }
        // 2. 命中袋码
        MesProBagCodeDO bag = bagCodeMapper.selectByCode(scanCode);
        if (bag != null && bag.getBatchId() != null) {
            return bridgeProBatch(bag.getBatchId());
        }
        // 3. 命中托盘码
        MesProPalletDO pallet = palletMapper.selectByCode(scanCode);
        if (pallet != null && pallet.getBatchId() != null) {
            return bridgeProBatch(pallet.getBatchId());
        }
        return null;
    }
    private MesWmBatchDO bridgeProBatch(Long proBatchId) {
        MesProBatchDO proBatch = proBatchService.getBatch(proBatchId);
        if (proBatch == null) {
            return null;
        }
        return mesWmBatchService.getOrCreateByProBatch(proBatch);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void processStockTakingDifference(Long id) {
        // 1. 校验任务存在且已完成
        MesWmStockTakingTaskDO task = validateStockTakingTaskExists(id);