云
3 天以前 5d818f39c862884b7087488d588fef5b7ce47386
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityServiceImpl.java
@@ -193,6 +193,8 @@
        if (qualifiedWarehouse == null) throw exception(WM_WAREHOUSE_NOT_EXISTS);
        if (!MesWmWarehouseTypeEnum.QUALIFIED.getType().equals(qualifiedWarehouse.getType()))
            throw exception(WM_WAREHOUSE_TYPE_NOT_QUALIFIED);
        // 提前校验合格库已配置库区/库位,避免复检审核放行时才失败
        resolveQualifiedLocation(qualifiedWarehouse);
        LocalDateTime now = LocalDateTime.now();
        Long operatorId = getLoginUserId();
@@ -252,6 +254,8 @@
        if (!MesWmWarehouseTypeEnum.QUALIFIED.getType().equals(qualifiedWarehouse.getType())) {
            throw exception(WM_WAREHOUSE_TYPE_NOT_QUALIFIED);
        }
        // 提前校验合格库已配置库区/库位,避免复检审核放行时才失败
        resolveQualifiedLocation(qualifiedWarehouse);
        Set<String> codes = new HashSet<>();
        boolean passed = true;
        MesQcSeedQualityDO quality = MesQcSeedQualityDO.builder().code(bag.getCode()).itemId(batch.getItemId())
@@ -296,12 +300,10 @@
        Long qualifiedLocationId = null;
        Long qualifiedAreaId = null;
        if (passed) {
            List<MesWmWarehouseLocationDO> locations = warehouseLocationService.getWarehouseLocationList(qualifiedWarehouse.getId());
            if (CollUtil.isNotEmpty(locations)) {
                qualifiedLocationId = locations.get(0).getId();
                List<MesWmWarehouseAreaDO> areas = warehouseAreaService.getWarehouseAreaList(qualifiedLocationId);
                if (CollUtil.isNotEmpty(areas)) qualifiedAreaId = areas.get(0).getId();
            }
            // 库存事务必须落到库区、库位,合格库缺少配置时提前给出可操作的提示
            Long[] target = resolveQualifiedLocation(qualifiedWarehouse);
            qualifiedLocationId = target[0];
            qualifiedAreaId = target[1];
        }
        // 按袋码粒度流转库存:锁定该袋在暂存库中的活动明细,禁止按批次任意扣减
        MesWmMaterialStockBagDO stockBag = materialStockBagMapper.selectActiveByBagCode(bag.getCode());
@@ -688,8 +690,8 @@
     *
     * @param tempStock            从暂存库扣减后返回的暂存记录(携带 item/batch/vendor 维度)
     * @param qualifiedWarehouseId 目标合格库仓库编号
     * @param qualifiedLocationId  目标合格库库区编号(未配置则为 null)
     * @param qualifiedAreaId      目标合格库库位编号(未配置则为 null)
     * @param qualifiedLocationId  目标合格库库区编号
     * @param qualifiedAreaId      目标合格库库位编号
     */
    private MesWmMaterialStockBagDO getOrCreateStockBag(MesProBagCodeDO bag, MesWmMaterialStockDO tempStock) {
        MesWmMaterialStockBagDO stockBag = materialStockBagMapper.selectByBagCode(bag.getCode());
@@ -706,6 +708,25 @@
        return stockBag;
    }
    /**
     * 解析合格库的默认入库库区与库位:取第一个同时配置了库位的非冻结库区。
     *
     * 质检按仓库维度选择入库目标,库区/库位由系统自动落点;合格库缺少可用库区或库位时,
     * 库存事务无法写入,直接提示管理员完善仓库配置。
     */
    private Long[] resolveQualifiedLocation(MesWmWarehouseDO qualifiedWarehouse) {
        List<MesWmWarehouseLocationDO> locations = warehouseLocationService.getWarehouseLocationList(qualifiedWarehouse.getId())
                .stream().filter(location -> !Boolean.TRUE.equals(location.getFrozen())).toList();
        if (CollUtil.isEmpty(locations))
            throw new IllegalArgumentException("合格库「" + qualifiedWarehouse.getName() + "」未配置可用库区,请先在仓库管理中完善库区与库位");
        for (MesWmWarehouseLocationDO location : locations) {
            List<MesWmWarehouseAreaDO> areas = warehouseAreaService.getWarehouseAreaList(location.getId())
                    .stream().filter(area -> !Boolean.TRUE.equals(area.getFrozen())).toList();
            if (CollUtil.isNotEmpty(areas)) return new Long[]{location.getId(), areas.get(0).getId()};
        }
        throw new IllegalArgumentException("合格库「" + qualifiedWarehouse.getName() + "」未配置可用库位,请先在仓库管理中完善库区与库位");
    }
    private MesWmMaterialStockDO getOrCreateQualifiedStock(MesWmMaterialStockDO tempStock, Long qualifiedWarehouseId,
                                         Long qualifiedLocationId, Long qualifiedAreaId) {
        MesWmMaterialStockDO qualified = materialStockMapper.selectQualifiedByCompositeKey(