src/main/java/com/ruoyi/common/handler/CustomTenantLineHandler.java
@@ -26,8 +26,18 @@ } } /** * 线程级临时忽略开关:某些 insert 场景下 jsqlparser 解析会抛 * ClassCastException: SetOperationList cannot be cast to PlainSelect, * 可在该线程内临时跳过租户插件(tenant_id 由 MybatisHandler 自动填充保证)。 */ public static final ThreadLocal<Boolean> TEMP_IGNORE = new ThreadLocal<>(); @Override public boolean ignoreTable(String tableName) { if (Boolean.TRUE.equals(TEMP_IGNORE.get())) { return true; } // 指定不需要添加过滤条件的表 Set<String> ignoreTables = IgnoreTableConfig.IGNORE_TABLES; return ignoreTables.contains(tableName); src/main/java/com/ruoyi/procurementrecord/pojo/CustomStorage.java
@@ -42,6 +42,29 @@ @TableField(exist = false) private String timeStr; // ===== 库存预警相关展示字段(来自 custom_storage_warning_record,非本表字段)===== /** 当前库存(页面列 currentStock,SQL 里由 availableStock 别名而来) */ @TableField(exist = false) private BigDecimal currentStock; /** 预警级别 */ @TableField(exist = false) private String warningLevel; /** 预警状态 */ @TableField(exist = false) private String warningStatus; /** 预警时间 */ @TableField(exist = false) private LocalDateTime warningTime; /** 预计缺货时间 */ @TableField(exist = false) private LocalDateTime expectedShortageTime; /** 建议类型 */ @TableField(exist = false) private String suggestionType; /** 建议内容 */ @TableField(exist = false) private String suggestionContent; /** * 待出库数量 */ src/main/java/com/ruoyi/procurementrecord/service/impl/ProcurementRecordOutServiceImpl.java
@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.handler.CustomTenantLineHandler; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.procurementrecord.dto.ProcurementRecordOutAdd; import com.ruoyi.procurementrecord.dto.ProcurementRecordOutPageDto; @@ -81,6 +82,11 @@ .updateUser(Long.valueOf(procurementRecordOutAdd.getUserId())) .updateTime(LocalDateTime.now()); ProcurementRecordOut saved = procurementRecordOut.build(); // 出库写入时临时跳过租户插件,避免 jsqlparser 解析异常 // (ClassCastException: SetOperationList cannot be cast to PlainSelect) // tenant_id 由 MybatisHandler 的 strictInsertFill 自动填充,不会丢 CustomTenantLineHandler.TEMP_IGNORE.set(Boolean.TRUE); try { this.save(saved); if (StringUtils.isNotEmpty(procurementRecordOutAdd.getRequisitionNum()) && saved.getId() != null) { ProcurementRecordOut upd = ProcurementRecordOut.builder() @@ -89,6 +95,9 @@ .build(); procurementRecordOutMapper.updateById(upd); } } finally { CustomTenantLineHandler.TEMP_IGNORE.remove(); } return 0; } src/main/resources/mapper/CustomStorageWarningRecordMapper.xml
@@ -22,7 +22,13 @@ sum(t1.tax_inclusive_total_price) as totalPrice, sum(t1.inbound_num) as inboundNum, sum(t1.inbound_num) as inboundNum0, SUM(t1.inbound_num) - COALESCE(SUM(t2.inbound_num), 0) AS availableStock SUM(t1.inbound_num) - COALESCE(SUM(t2.inbound_num), 0) AS currentStock, ANY_VALUE(cswr.warning_level) AS warningLevel, ANY_VALUE(cswr.warning_status) AS warningStatus, ANY_VALUE(cswr.warning_time) AS warningTime, ANY_VALUE(cswr.expectedShortageTime) AS expectedShortageTime, ANY_VALUE(cswr.suggestion_type) AS suggestionType, ANY_VALUE(cswr.suggestion_content) AS suggestionContent from custom_storage t1 left join procurement_record_out t2 on t1.id = t2.procurement_record_storage_id and t2.type = 3 inner join custom_storage_warning_record cswr on t1.id = cswr.custom_storage_id