diff --git a/finance/src/main/java/com/baiyue/finance/mapper/FinanceFeeSourceReadMapper.java b/finance/src/main/java/com/baiyue/finance/mapper/FinanceFeeSourceReadMapper.java
new file mode 100644
index 000000000..4fa153600
--- /dev/null
+++ b/finance/src/main/java/com/baiyue/finance/mapper/FinanceFeeSourceReadMapper.java
@@ -0,0 +1,60 @@
+package com.baiyue.finance.mapper;
+
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+import java.util.List;
+import java.util.Map;
+
+/** 费用池按稳定来源读取当前版本,历史快照保留在同一费用的操作记录中。 */
+@Mapper
+public interface FinanceFeeSourceReadMapper {
+ String GENERATED = "(EXISTS(SELECT 1 FROM fin_bill_line bl WHERE bl.source_id=f.id AND bl.source_version=f.source_fee_version))";
+ String STATUS = "CASE WHEN f.status='AVAILABLE' AND " + GENERATED + " THEN 'BILLED' ELSE f.status END";
+ String BUSINESS_DATE = "CAST(JSON_UNQUOTE(JSON_EXTRACT(f.source_snapshot,'$.businessDate')) AS DATE)";
+ String FILTER = " FROM fin_fee_source f WHERE 1=1 " +
+ "" +
+ " AND f.status<>'SUPERSEDED' AND NOT EXISTS(SELECT 1 FROM fin_fee_source newer" +
+ " WHERE newer.source_system=f.source_system AND newer.source_type=f.source_type" +
+ " AND newer.source_fee_id=f.source_fee_id AND newer.source_fee_version>f.source_fee_version)" +
+ "" +
+ " AND f.customer_id=#{customerId}" +
+ " AND f.direction=#{direction}" +
+ " AND f.review_status=#{reviewStatus}" +
+ " AND " + STATUS + "=#{status}" +
+ " AND " + GENERATED + "=#{statementGenerated}" +
+ " AND " + BUSINESS_DATE + ">=#{dateFrom}" +
+ " AND " + BUSINESS_DATE + "<=#{dateTo}" +
+ " AND (f.source_no LIKE CONCAT('%',#{keyword},'%')" +
+ " OR f.fee_item_name LIKE CONCAT('%',#{keyword},'%')" +
+ " OR JSON_UNQUOTE(JSON_EXTRACT(f.source_snapshot,'$.customerName')) LIKE CONCAT('%',#{keyword},'%')" +
+ " OR JSON_UNQUOTE(JSON_EXTRACT(f.source_snapshot,'$.inboundCode')) LIKE CONCAT('%',#{keyword},'%')" +
+ " OR JSON_UNQUOTE(JSON_EXTRACT(f.source_snapshot,'$.containerNo')) LIKE CONCAT('%',#{keyword},'%')" +
+ " OR JSON_UNQUOTE(JSON_EXTRACT(f.source_snapshot,'$.supplierName')) LIKE CONCAT('%',#{keyword},'%'))";
+
+ /** 筛选和计数共用当前版本条件,不能先分页再去重。 */
+ @Select("")
+ long count(Map filters);
+
+ /** 应收、应付分别展示当前快照;同名但来源费用号不同的费用不合并。 */
+ @Select("")
+ List