feat(mes): 出货检验单客户改为选填,未关联客户的单据不受客户数据权限限制

- 保存接口去掉客户必填校验,导入模板「客户名称」列改为选填
- 导入解析客户名称留空时返回空客户,跳过客户数据权限校验
- 列表按客户数据权限过滤时,未关联客户的出货检验单始终可见
- 出货前校验按客户查询时区分「指定客户」与「未关联客户」两种情况

Co-Authored-By: Claude Code <noreply@anthropic.com>
已修改5个文件
25 ■■■■■ 文件已修改
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/vo/MesQcOqcImportExcelVO.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/vo/MesQcOqcSaveReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/oqc/MesQcOqcMapper.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/imports/MesQcImportHelper.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/oqc/MesQcOqcServiceImpl.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/vo/MesQcOqcImportExcelVO.java
@@ -37,7 +37,7 @@
    private String itemCode;
    @ExcelProperty("客户名称")
    @Schema(description = "客户名称,需与 CRM 客户管理中的名称一致", requiredMode = Schema.RequiredMode.REQUIRED, example = "示例客户有限公司")
    @Schema(description = "客户名称,选填;填写时需与 CRM 客户管理中的名称一致", example = "示例客户有限公司")
    private String clientName;
    @ExcelProperty("批次号")
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/vo/MesQcOqcSaveReqVO.java
@@ -37,8 +37,7 @@
    // ========== 客户 ==========
    @Schema(description = "客户 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
    @NotNull(message = "客户不能为空")
    @Schema(description = "客户 ID,可为空:不关联客户的出货检验单只做内部出货记录", example = "10")
    private Long clientId;
    // ========== 物料 ==========
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/oqc/MesQcOqcMapper.java
@@ -43,10 +43,13 @@
                .betweenIfPresent(MesQcOqcDO::getInspectDate, reqVO.getInspectDate())
                .orderByDesc(MesQcOqcDO::getId);
        if (permittedClientIds != null) {
            // 客户非必填:未关联客户的出货检验单不属于任何客户,不受客户数据权限限制,始终可见
            if (CollUtil.isEmpty(permittedClientIds)) {
                return PageResult.empty();
                wrapper.isNull(MesQcOqcDO::getClientId);
            } else {
                wrapper.and(w -> w.in(MesQcOqcDO::getClientId, permittedClientIds)
                        .or().isNull(MesQcOqcDO::getClientId));
            }
            wrapper.in(MesQcOqcDO::getClientId, permittedClientIds);
        }
        return selectPage(reqVO, wrapper);
    }
@@ -62,7 +65,8 @@
                                                   LocalDateTime outDate) {
        return selectList(new LambdaQueryWrapperX<MesQcOqcDO>()
                .eq(MesQcOqcDO::getItemId, itemId)
                .eq(MesQcOqcDO::getClientId, clientId)
                .eq(clientId != null, MesQcOqcDO::getClientId, clientId)
                .isNull(clientId == null, MesQcOqcDO::getClientId)
                .eq(batchCode != null, MesQcOqcDO::getBatchCode, batchCode)
                .isNull(batchCode == null, MesQcOqcDO::getBatchCode)
                .eq(MesQcOqcDO::getOutDate, outDate)
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/imports/MesQcImportHelper.java
@@ -174,11 +174,11 @@
    }
    /**
     * 解析客户编号,基于客户名称
     * 解析客户编号,基于客户名称(选填:客户名称留空时返回 null,表示该检验单不关联客户)
     */
    public Long resolveClientId(String clientName) {
        if (StrUtil.isBlank(clientName)) {
            throw new IllegalArgumentException("客户名称不能为空:请填写模板中该行的「客户名称」列");
            return null;
        }
        if (customerNameMap == null) {
            customerNameMap = new HashMap<>();
@@ -205,6 +205,10 @@
     * 出货检验单列表按客户数据权限过滤,权限外的客户导入后本人在列表中看不到该单据,因此提前拦截。
     */
    public void validateClientPermission(Long clientId, String clientName) {
        // 客户选填:未填写客户的检验单不属于任何客户,不受客户数据权限限制
        if (clientId == null) {
            return;
        }
        if (!clientPermissionLoaded) {
            List<Long> permittedIds = crmCustomerApi.getPermittedCustomerIds();
            permittedClientIds = permittedIds == null ? null : new HashSet<>(permittedIds);
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/oqc/MesQcOqcServiceImpl.java
@@ -528,7 +528,7 @@
        reqVO.setName(row.getName().trim());
        reqVO.setItemId(qcImportHelper.resolveItemId(row.getItemCode()));
        Long clientId = qcImportHelper.resolveClientId(row.getClientName());
        qcImportHelper.validateClientPermission(clientId, row.getClientName().trim());
        qcImportHelper.validateClientPermission(clientId, StrUtil.trimToNull(row.getClientName()));
        reqVO.setClientId(clientId);
        reqVO.setBatchCode(StrUtil.trimToNull(row.getBatchCode()));
        reqVO.setTemplateId(qcImportHelper.resolveTemplateId(row.getTemplateName()));