Merge remote-tracking branch 'origin/dev_business_新高电力' into dev_business_新高电力
已修改43个文件
254 ■■■■■ 文件已修改
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/knowledge/AiKnowledgeImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/apikey/AiApiKeyImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/model/AiModelImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-bi/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/config/vo/BiChartConfigImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-bi/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/config/vo/BiDataSourceConfigImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-bi/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/decision/vo/DecisionAlertRuleImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-bi/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/decision/vo/DecisionKpiDefinitionImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/attach/vo/attach/BpmBusinessAttachImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategoryImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/expression/BpmProcessExpressionImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/listener/BpmProcessListenerImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/credit/vo/CrmCreditRatingImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/salesTarget/vo/CrmSalesTargetImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/account/ErpAccountImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseRequestController.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/invoice/ErpPurchaseInvoiceImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/order/ErpPurchaseOrderImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/plan/ErpPurchasePlanImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/request/ErpPurchaseRequestImportReqVO.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/request/ErpPurchaseRequestImportRespVO.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/supplier/ErpSupplierImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseRequestServiceImpl.java 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/job/JobImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/vo/MdmItemImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/unit/vo/MdmUnitMeasureImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/certificate/vo/SrmSupplierCertificateImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/supplier/vo/SrmSupplierImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/data/DictDataImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/type/DictTypeImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notice/vo/NoticeImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/menu/MenuImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RoleImportReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/knowledge/AiKnowledgeImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/apikey/AiApiKeyImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/model/AiModelImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-bi/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/config/vo/BiChartConfigImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-bi/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/config/vo/BiDataSourceConfigImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-bi/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/decision/vo/DecisionAlertRuleImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-bi/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/decision/vo/DecisionKpiDefinitionImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/attach/vo/attach/BpmBusinessAttachImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategoryImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/expression/BpmProcessExpressionImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/listener/BpmProcessListenerImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessImportReqVO.java
@@ -16,10 +16,9 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
    @Schema(description = "负责人", example = "1")
    private Long ownerUserId; // 为 null 则默认为当前操作人
}
}
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueImportReqVO.java
@@ -16,10 +16,9 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
    @Schema(description = "负责人", example = "1")
    private Long ownerUserId; // 为 null 则默认为当前操作人
}
}
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactImportReqVO.java
@@ -16,10 +16,9 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
    @Schema(description = "负责人", example = "1")
    private Long ownerUserId; // 为 null 则默认为当前操作人
}
}
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractImportReqVO.java
@@ -16,10 +16,9 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
    @Schema(description = "负责人", example = "1")
    private Long ownerUserId; // 为 null 则默认为当前操作人
}
}
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/credit/vo/CrmCreditRatingImportReqVO.java
@@ -16,10 +16,9 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
    @Schema(description = "操作人", example = "1")
    private Long operatorId; // 为 null 则默认为当前操作人
}
}
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportReqVO.java
@@ -16,10 +16,9 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
    @Schema(description = "负责人", example = "1")
    private Long ownerUserId; // 为 null 则客户进入公海
}
}
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/salesTarget/vo/CrmSalesTargetImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/account/ErpAccountImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseRequestController.java
@@ -40,6 +40,7 @@
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -142,9 +143,12 @@
    @Operation(summary = "获得导入采购申请模板")
    public void importTemplate(HttpServletResponse response) throws IOException {
        // 手动创建导出 demo
        // 注意:requestTime 是导入时的必填校验项,模板里必须给出示例值,
        // 否则用户照着模板填完导入必然报「申请时间不能为空」。
        List<ErpPurchaseRequestImportExcelVO> list = Arrays.asList(
                ErpPurchaseRequestImportExcelVO.builder().no("CGSQ-示例-001").requestTime(null)
                        .requestReason("").supplierName("").discountPercent(null).depositPrice(null)
                ErpPurchaseRequestImportExcelVO.builder().no("CGSQ-示例-001")
                        .requestTime(LocalDateTime.now().withNano(0))
                        .requestReason("需求说明").supplierName("").discountPercent(null).depositPrice(null)
                        .remark("").productCode("").productUnitCode("").productPrice(null)
                        .count(null).taxPercent(null).demandTime(null).qcCheckFlag(false)
                        .itemRemark("").build()
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/invoice/ErpPurchaseInvoiceImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新(单据导入为新建,暂不覆盖已有单据)", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/order/ErpPurchaseOrderImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新(单据导入为新建,暂不覆盖已有单据)", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/plan/ErpPurchasePlanImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新(单据导入为新建,暂不覆盖已有单据)", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/request/ErpPurchaseRequestImportReqVO.java
@@ -15,8 +15,7 @@
    @NotNull(message = "Excel 文件不能为空")
    private MultipartFile file;
    @Schema(description = "是否支持更新(单据导入为新建,暂不覆盖已有单据)", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    @Schema(description = "是否支持更新(单据导入为新建,暂不覆盖已有单据;该字段当前未参与业务逻辑,可传可不传)", example = "true")
    private Boolean updateSupport;
}
}
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/request/ErpPurchaseRequestImportRespVO.java
@@ -15,7 +15,22 @@
    @Schema(description = "创建成功的采购申请号数组", requiredMode = Schema.RequiredMode.REQUIRED)
    private List<String> createPurchaseRequestNos;
    @Schema(description = "导入失败的采购申请集合,key 为单号,value 为失败原因", requiredMode = Schema.RequiredMode.REQUIRED)
    @Schema(description = "导入失败的采购申请集合,key 为单号或行号,value 为失败原因", requiredMode = Schema.RequiredMode.REQUIRED)
    private Map<String, String> failurePurchaseRequestNos;
    /**
     * 被跳过的行,key 为 Excel 中的实际行号(如「第3行」),value 为跳过原因。
     *
     * 历史实现会因「物料编码为空」静默丢弃这些行,导致用户看到「导入成功」但数据丢失。
     * 这里显式返回,前端必须展示,避免数据无声消失。
     */
    @Schema(description = "被跳过的行(未导入),key 为 Excel 行号,value 为跳过原因")
    private Map<String, String> skippedRows;
    @Schema(description = "Excel 中实际有数据的行数(不含表头与完全空白行)")
    private Integer totalRows;
    @Schema(description = "成功导入的行数")
    private Integer successRows;
}
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/supplier/ErpSupplierImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新(单据导入为新建,暂不覆盖已有单据)", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java
@@ -98,6 +98,7 @@
    ErrorCode PURCHASE_REQUEST_IMPORT_SUPPLIER_NOT_EXISTS = new ErrorCode(1_030_104_042, "供应商【{}】不存在!");
    ErrorCode PURCHASE_REQUEST_IMPORT_PRODUCT_NOT_EXISTS = new ErrorCode(1_030_104_043, "物料编码【{}】不存在!");
    ErrorCode PURCHASE_REQUEST_IMPORT_UNIT_NOT_EXISTS = new ErrorCode(1_030_104_044, "单位编码【{}】不存在!");
    ErrorCode PURCHASE_REQUEST_IMPORT_ALL_ROWS_SKIPPED = new ErrorCode(1_030_104_045, "所有行均未导入,被跳过的行:{}。请检查物料编码是否填写。");
    // ========== ERP 采购来票(1-030-105-000) ==========
    ErrorCode PURCHASE_INVOICE_NOT_EXISTS = new ErrorCode(1_030_105_000, "来票不存在");
@@ -268,4 +269,4 @@
    ErrorCode WAREHOUSE_MAPPING_NOT_EXISTS = new ErrorCode(1_030_700_000, "仓库映射不存在");
    ErrorCode WAREHOUSE_MAPPING_EXISTS = new ErrorCode(1_030_700_001, "该ERP仓库已存在映射配置");
}
}
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseRequestServiceImpl.java
@@ -522,18 +522,51 @@
    @Override
    public ErpPurchaseRequestImportRespVO importPurchaseRequestList(List<ErpPurchaseRequestImportExcelVO> importRequests,
                                                                    ErpPurchaseRequestImportReqVO importReqVO) {
        // 1. 校验非空(过滤完全空白的行)
        importRequests = filterList(importRequests, item -> StrUtil.isNotBlank(item.getProductCode()));
        if (CollUtil.isEmpty(importRequests)) {
            throw exception(PURCHASE_REQUEST_IMPORT_LIST_IS_EMPTY);
        }
        // 1. 逐行分类:有效行 / 被跳过的行。
        //    这里不再用 filterList 静默丢弃「物料编码为空」的行 —— 那会让用户看到「导入成功」
        //    但数据无声消失。被跳过的行必须带 Excel 原始行号返回给前端。
        ErpPurchaseRequestImportRespVO respVO = ErpPurchaseRequestImportRespVO.builder()
                .createPurchaseRequestNos(new ArrayList<>())
                .failurePurchaseRequestNos(new LinkedHashMap<>())
                .skippedRows(new LinkedHashMap<>())
                .build();
        List<ImportRow> validRows = new ArrayList<>();
        for (int i = 0; i < importRequests.size(); i++) {
            ErpPurchaseRequestImportExcelVO row = importRequests.get(i);
            int excelRowNo = i + 2; // +1 转 1 基,+1 跳过表头
            String rowLabel = "第" + excelRowNo + "行";
            // 1.1 完全空白的行(所有列都没有值):Excel 常在末尾留空行,静默跳过即可
            if (isBlankRow(row)) {
                continue;
            }
            // 1.2 物料编码为空:业务上无法定位物料,跳过并明确告知用户
            if (StrUtil.isBlank(row.getProductCode())) {
                respVO.getSkippedRows().put(rowLabel, "物料编码为空,该行未导入");
                continue;
            }
            validRows.add(new ImportRow(excelRowNo, row));
        }
        respVO.setTotalRows(validRows.size() + respVO.getSkippedRows().size());
        if (CollUtil.isEmpty(validRows)) {
            // 没有任何一行可导入:直接报错。
            // 若是有行因「物料编码为空」被跳过,异常信息里带上行号,帮助用户定位。
            if (CollUtil.isNotEmpty(respVO.getSkippedRows())) {
                throw exception(PURCHASE_REQUEST_IMPORT_ALL_ROWS_SKIPPED,
                        String.join("、", respVO.getSkippedRows().keySet()));
            }
            throw exception(PURCHASE_REQUEST_IMPORT_LIST_IS_EMPTY);
        }
        // 2. 按「单号」分组:相同单号的多行合并成一张采购申请;单号为空时每行各自成一张申请
        List<List<ErpPurchaseRequestImportExcelVO>> groups = new ArrayList<>();
        List<List<ImportRow>> groups = new ArrayList<>();
        Map<String, Integer> groupIndexMap = new LinkedHashMap<>();
        int rowIndex = 0;
        for (ErpPurchaseRequestImportExcelVO row : importRequests) {
            rowIndex++;
            String groupKey = StrUtil.isNotBlank(row.getNo()) ? row.getNo() : ("__row_" + rowIndex);
        for (ImportRow row : validRows) {
            String no = row.data.getNo();
            String groupKey = StrUtil.isNotBlank(no) ? no : ("__row_" + row.excelRowNo);
            Integer index = groupIndexMap.get(groupKey);
            if (index == null) {
                index = groups.size();
@@ -542,23 +575,65 @@
            }
            groups.get(index).add(row);
        }
        // 3. 逐组合并创建采购申请
        ErpPurchaseRequestImportRespVO respVO = ErpPurchaseRequestImportRespVO.builder()
                .createPurchaseRequestNos(new ArrayList<>())
                .failurePurchaseRequestNos(new LinkedHashMap<>())
                .build();
        for (List<ErpPurchaseRequestImportExcelVO> group : groups) {
            String groupKey = StrUtil.isNotBlank(group.get(0).getNo()) ? group.get(0).getNo()
                    : "第" + (importRequests.indexOf(group.get(0)) + 1) + "行";
        for (List<ImportRow> group : groups) {
            ImportRow firstRow = group.get(0);
            // 失败/跳过的标识优先用单号,没有单号则用 Excel 里的真实行号
            String groupKey = StrUtil.isNotBlank(firstRow.data.getNo())
                    ? firstRow.data.getNo() : "第" + firstRow.excelRowNo + "行";
            try {
                ErpPurchaseRequestSaveReqVO createReqVO = buildPurchaseRequestImportSaveReqVO(group);
                ErpPurchaseRequestSaveReqVO createReqVO = buildPurchaseRequestImportSaveReqVO(
                        convertList(group, ImportRow::getData));
                Long requestId = createPurchaseRequest(createReqVO);
                respVO.getCreatePurchaseRequestNos().add(purchaseRequestMapper.selectById(requestId).getNo());
                respVO.setSuccessRows(respVO.getSuccessRows() == null
                        ? group.size() : respVO.getSuccessRows() + group.size());
            } catch (ServiceException ex) {
                // 业务校验失败:记录原因,继续处理下一组
                respVO.getFailurePurchaseRequestNos().put(groupKey, ex.getMessage());
            } catch (Exception ex) {
                // 非业务异常(如远程调用 NPE、数据解析失败):不能让整个导入 500,
                // 记录为失败并继续,保证其它能导的行正常入库
                log.error("[importPurchaseRequestList] 导入行({}) 发生非业务异常", groupKey, ex);
                respVO.getFailurePurchaseRequestNos().put(groupKey,
                        "导入失败:" + (ex instanceof NullPointerException ? "数据解析异常,请检查物料/单位编码" : ex.getMessage()));
            }
        }
        return respVO;
    }
    /**
     * 判断一行是否完全空白(所有业务列都没有值)
     */
    private boolean isBlankRow(ErpPurchaseRequestImportExcelVO row) {
        return StrUtil.isBlank(row.getNo())
                && StrUtil.isBlank(row.getProductCode())
                && StrUtil.isBlank(row.getProductUnitCode())
                && row.getRequestTime() == null
                && row.getCount() == null
                && row.getProductPrice() == null
                && StrUtil.isBlank(row.getSupplierName())
                && StrUtil.isBlank(row.getRequestReason())
                && StrUtil.isBlank(row.getRemark())
                && StrUtil.isBlank(row.getItemRemark());
    }
    /**
     * 导入行包装:携带 Excel 中的真实行号,用于错误提示定位。
     */
    private static class ImportRow {
        private final int excelRowNo;
        private final ErpPurchaseRequestImportExcelVO data;
        private ImportRow(int excelRowNo, ErpPurchaseRequestImportExcelVO data) {
            this.excelRowNo = excelRowNo;
            this.data = data;
        }
        private ErpPurchaseRequestImportExcelVO getData() {
            return data;
        }
    }
    /**
@@ -612,4 +687,4 @@
                .setItems(items);
    }
}
}
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/job/JobImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/vo/MdmItemImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/unit/vo/MdmUnitMeasureImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/certificate/vo/SrmSupplierCertificateImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/controller/admin/supplier/vo/SrmSupplierImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/data/DictDataImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/type/DictTypeImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notice/vo/NoticeImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/menu/MenuImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RoleImportReqVO.java
@@ -16,7 +16,6 @@
    private MultipartFile file;
    @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
    @NotNull(message = "是否支持更新不能为空")
    private Boolean updateSupport;
}
}