补充流水明细查询Mapper与动态SQL

This commit is contained in:
wkc
2026-03-10 16:06:44 +08:00
parent b498137206
commit cfc3545fc7
3 changed files with 326 additions and 0 deletions

View File

@@ -1,8 +1,12 @@
package com.ruoyi.ccdi.project.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.ccdi.project.domain.entity.CcdiBankStatement;
import com.ruoyi.ccdi.project.domain.dto.CcdiBankStatementQueryDTO;
import com.ruoyi.ccdi.project.domain.vo.CcdiBankStatementDetailVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiBankStatementFilterOptionsVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiBankStatementListVO;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@@ -26,5 +30,12 @@ public interface CcdiBankStatementMapper extends BaseMapper<CcdiBankStatement> {
int deleteByProjectIdAndBatchId(@Param("projectId") Long projectId,
@Param("batchId") Integer batchId);
Page<CcdiBankStatementListVO> selectStatementPage(Page<CcdiBankStatementListVO> page,
@Param("query") CcdiBankStatementQueryDTO query);
List<CcdiBankStatementListVO> selectStatementListForExport(@Param("query") CcdiBankStatementQueryDTO query);
CcdiBankStatementDetailVO selectStatementDetailById(@Param("bankStatementId") Long bankStatementId);
CcdiBankStatementFilterOptionsVO selectFilterOptions(@Param("projectId") Long projectId);
}

View File

@@ -59,6 +59,302 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
from ccdi_bank_statement
</sql>
<resultMap id="CcdiBankStatementListVOResultMap" type="com.ruoyi.ccdi.project.domain.vo.CcdiBankStatementListVO">
<id property="bankStatementId" column="bankStatementId"/>
<result property="trxDate" column="trxDate"/>
<result property="leAccountNo" column="leAccountNo"/>
<result property="leAccountName" column="leAccountName"/>
<result property="customerAccountName" column="customerAccountName"/>
<result property="customerAccountNo" column="customerAccountNo"/>
<result property="userMemo" column="userMemo"/>
<result property="cashType" column="cashType"/>
<result property="displayAmount" column="displayAmount"/>
</resultMap>
<resultMap id="CcdiBankStatementDetailVOResultMap" type="com.ruoyi.ccdi.project.domain.vo.CcdiBankStatementDetailVO">
<id property="bankStatementId" column="bankStatementId"/>
<result property="projectId" column="projectId"/>
<result property="trxDate" column="trxDate"/>
<result property="currency" column="currency"/>
<result property="leAccountNo" column="leAccountNo"/>
<result property="leAccountName" column="leAccountName"/>
<result property="customerAccountName" column="customerAccountName"/>
<result property="customerAccountNo" column="customerAccountNo"/>
<result property="customerBank" column="customerBank"/>
<result property="customerReference" column="customerReference"/>
<result property="userMemo" column="userMemo"/>
<result property="bankComments" column="bankComments"/>
<result property="bankTrxNumber" column="bankTrxNumber"/>
<result property="bank" column="bank"/>
<result property="cashType" column="cashType"/>
<result property="amountDr" column="amountDr"/>
<result property="amountCr" column="amountCr"/>
<result property="amountBalance" column="amountBalance"/>
<result property="displayAmount" column="displayAmount"/>
<result property="trxFlag" column="trxFlag"/>
<result property="trxType" column="trxType"/>
<result property="exceptionType" column="exceptionType"/>
<result property="internalFlag" column="internalFlag"/>
<result property="paymentMethod" column="paymentMethod"/>
<result property="cretNo" column="cretNo"/>
<result property="createDate" column="createDate"/>
</resultMap>
<resultMap id="CcdiBankStatementFilterOptionsVOResultMap"
type="com.ruoyi.ccdi.project.domain.vo.CcdiBankStatementFilterOptionsVO">
<collection property="ourSubjectOptions"
column="{projectId=project_id}"
select="selectOurSubjectOptions"/>
<collection property="ourBankOptions"
column="{projectId=project_id}"
select="selectOurBankOptions"/>
<collection property="ourAccountOptions"
column="{projectId=project_id}"
select="selectOurAccountOptions"/>
</resultMap>
<sql id="parsedTrxDateExpr">
CASE
WHEN bs.TRX_DATE IS NULL OR TRIM(bs.TRX_DATE) = '' THEN NULL
WHEN LENGTH(TRIM(bs.TRX_DATE)) = 10 THEN STR_TO_DATE(CONCAT(TRIM(bs.TRX_DATE), ' 00:00:00'), '%Y-%m-%d %H:%i:%s')
ELSE STR_TO_DATE(TRIM(bs.TRX_DATE), '%Y-%m-%d %H:%i:%s')
END
</sql>
<sql id="displayAmountExpr">
CASE
WHEN IFNULL(bs.AMOUNT_CR, 0) > 0 THEN IFNULL(bs.AMOUNT_CR, 0)
ELSE 0 - IFNULL(bs.AMOUNT_DR, 0)
END
</sql>
<sql id="absoluteAmountExpr">
CASE
WHEN IFNULL(bs.AMOUNT_CR, 0) > 0 THEN IFNULL(bs.AMOUNT_CR, 0)
ELSE IFNULL(bs.AMOUNT_DR, 0)
END
</sql>
<sql id="statementListColumns">
bs.bank_statement_id AS bankStatementId,
bs.TRX_DATE AS trxDate,
bs.LE_ACCOUNT_NO AS leAccountNo,
bs.LE_ACCOUNT_NAME AS leAccountName,
bs.CUSTOMER_ACCOUNT_NAME AS customerAccountName,
bs.CUSTOMER_ACCOUNT_NO AS customerAccountNo,
bs.USER_MEMO AS userMemo,
bs.CASH_TYPE AS cashType,
<include refid="displayAmountExpr"/> AS displayAmount
</sql>
<sql id="statementFilterWhere">
bs.project_id = #{query.projectId}
<if test="query.tabType == 'in'">
AND IFNULL(bs.AMOUNT_CR, 0) > 0
</if>
<if test="query.tabType == 'out'">
AND IFNULL(bs.AMOUNT_DR, 0) > 0
</if>
<if test="query.transactionStartTime != null and query.transactionStartTime != ''">
AND <include refid="parsedTrxDateExpr"/> <![CDATA[ >= ]]>
CASE
WHEN LENGTH(TRIM(#{query.transactionStartTime})) = 10
THEN STR_TO_DATE(CONCAT(TRIM(#{query.transactionStartTime}), ' 00:00:00'), '%Y-%m-%d %H:%i:%s')
ELSE STR_TO_DATE(TRIM(#{query.transactionStartTime}), '%Y-%m-%d %H:%i:%s')
END
</if>
<if test="query.transactionEndTime != null and query.transactionEndTime != ''">
AND <include refid="parsedTrxDateExpr"/> <![CDATA[ <= ]]>
CASE
WHEN LENGTH(TRIM(#{query.transactionEndTime})) = 10
THEN STR_TO_DATE(CONCAT(TRIM(#{query.transactionEndTime}), ' 23:59:59'), '%Y-%m-%d %H:%i:%s')
ELSE STR_TO_DATE(TRIM(#{query.transactionEndTime}), '%Y-%m-%d %H:%i:%s')
END
</if>
<if test="(query.counterpartyName != null and query.counterpartyName != '') or query.counterpartyNameEmpty">
AND (
<if test="query.counterpartyName != null and query.counterpartyName != ''">
bs.CUSTOMER_ACCOUNT_NAME LIKE CONCAT('%', TRIM(#{query.counterpartyName}), '%')
</if>
<if test="query.counterpartyName != null and query.counterpartyName != '' and query.counterpartyNameEmpty">
OR
</if>
<if test="query.counterpartyNameEmpty">
bs.CUSTOMER_ACCOUNT_NAME IS NULL OR TRIM(bs.CUSTOMER_ACCOUNT_NAME) = ''
</if>
)
</if>
<if test="(query.userMemo != null and query.userMemo != '') or query.userMemoEmpty">
AND (
<if test="query.userMemo != null and query.userMemo != ''">
bs.USER_MEMO LIKE CONCAT('%', TRIM(#{query.userMemo}), '%')
</if>
<if test="query.userMemo != null and query.userMemo != '' and query.userMemoEmpty">
OR
</if>
<if test="query.userMemoEmpty">
bs.USER_MEMO IS NULL OR TRIM(bs.USER_MEMO) = ''
</if>
)
</if>
<if test="query.ourSubjects != null and query.ourSubjects.size() > 0">
AND bs.LE_ACCOUNT_NAME IN
<foreach collection="query.ourSubjects" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</if>
<if test="query.ourBanks != null and query.ourBanks.size() > 0">
AND bs.BANK IN
<foreach collection="query.ourBanks" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</if>
<if test="query.ourAccounts != null and query.ourAccounts.size() > 0">
AND bs.LE_ACCOUNT_NO IN
<foreach collection="query.ourAccounts" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</if>
<if test="query.amountMin != null">
AND <include refid="absoluteAmountExpr"/> <![CDATA[ >= ]]> #{query.amountMin}
</if>
<if test="query.amountMax != null">
AND <include refid="absoluteAmountExpr"/> <![CDATA[ <= ]]> #{query.amountMax}
</if>
<if test="(query.counterpartyAccount != null and query.counterpartyAccount != '') or query.counterpartyAccountEmpty">
AND (
<if test="query.counterpartyAccount != null and query.counterpartyAccount != ''">
bs.CUSTOMER_ACCOUNT_NO LIKE CONCAT('%', TRIM(#{query.counterpartyAccount}), '%')
</if>
<if test="query.counterpartyAccount != null and query.counterpartyAccount != '' and query.counterpartyAccountEmpty">
OR
</if>
<if test="query.counterpartyAccountEmpty">
bs.CUSTOMER_ACCOUNT_NO IS NULL OR TRIM(bs.CUSTOMER_ACCOUNT_NO) = ''
</if>
)
</if>
<if test="(query.transactionType != null and query.transactionType != '') or query.transactionTypeEmpty">
AND (
<if test="query.transactionType != null and query.transactionType != ''">
bs.CASH_TYPE LIKE CONCAT('%', TRIM(#{query.transactionType}), '%')
</if>
<if test="query.transactionType != null and query.transactionType != '' and query.transactionTypeEmpty">
OR
</if>
<if test="query.transactionTypeEmpty">
bs.CASH_TYPE IS NULL OR TRIM(bs.CASH_TYPE) = ''
</if>
)
</if>
</sql>
<sql id="statementOrderBy">
<choose>
<when test="query.orderBy == 'amount' and query.orderDirection == 'asc'">
ORDER BY <include refid="absoluteAmountExpr"/> ASC, bs.bank_statement_id ASC
</when>
<when test="query.orderBy == 'amount' and query.orderDirection == 'desc'">
ORDER BY <include refid="absoluteAmountExpr"/> DESC, bs.bank_statement_id DESC
</when>
<when test="query.orderDirection == 'asc'">
ORDER BY <include refid="parsedTrxDateExpr"/> ASC, bs.bank_statement_id ASC
</when>
<otherwise>
ORDER BY <include refid="parsedTrxDateExpr"/> DESC, bs.bank_statement_id DESC
</otherwise>
</choose>
</sql>
<select id="selectStatementPage" resultMap="CcdiBankStatementListVOResultMap">
SELECT
<include refid="statementListColumns"/>
FROM ccdi_bank_statement bs
<where>
<include refid="statementFilterWhere"/>
</where>
<include refid="statementOrderBy"/>
</select>
<select id="selectStatementListForExport" resultMap="CcdiBankStatementListVOResultMap">
SELECT
<include refid="statementListColumns"/>
FROM ccdi_bank_statement bs
<where>
<include refid="statementFilterWhere"/>
</where>
<include refid="statementOrderBy"/>
</select>
<select id="selectStatementDetailById" resultMap="CcdiBankStatementDetailVOResultMap">
SELECT
bs.bank_statement_id AS bankStatementId,
bs.project_id AS projectId,
bs.TRX_DATE AS trxDate,
bs.CURRENCY AS currency,
bs.LE_ACCOUNT_NO AS leAccountNo,
bs.LE_ACCOUNT_NAME AS leAccountName,
bs.CUSTOMER_ACCOUNT_NAME AS customerAccountName,
bs.CUSTOMER_ACCOUNT_NO AS customerAccountNo,
bs.customer_bank AS customerBank,
bs.customer_reference AS customerReference,
bs.USER_MEMO AS userMemo,
bs.BANK_COMMENTS AS bankComments,
bs.BANK_TRX_NUMBER AS bankTrxNumber,
bs.BANK AS bank,
bs.CASH_TYPE AS cashType,
bs.AMOUNT_DR AS amountDr,
bs.AMOUNT_CR AS amountCr,
bs.AMOUNT_BALANCE AS amountBalance,
<include refid="displayAmountExpr"/> AS displayAmount,
bs.TRX_FLAG AS trxFlag,
bs.TRX_TYPE AS trxType,
bs.EXCEPTION_TYPE AS exceptionType,
bs.internal_flag AS internalFlag,
bs.payment_method AS paymentMethod,
bs.cret_no AS cretNo,
bs.CREATE_DATE AS createDate
FROM ccdi_bank_statement bs
WHERE bs.bank_statement_id = #{bankStatementId}
</select>
<select id="selectFilterOptions" resultMap="CcdiBankStatementFilterOptionsVOResultMap">
SELECT #{projectId} AS project_id
</select>
<select id="selectOurSubjectOptions" resultType="com.ruoyi.ccdi.project.domain.vo.CcdiBankStatementOptionVO">
SELECT DISTINCT
TRIM(bs.LE_ACCOUNT_NAME) AS label,
TRIM(bs.LE_ACCOUNT_NAME) AS value
FROM ccdi_bank_statement bs
WHERE bs.project_id = #{projectId}
AND bs.LE_ACCOUNT_NAME IS NOT NULL
AND TRIM(bs.LE_ACCOUNT_NAME) != ''
ORDER BY TRIM(bs.LE_ACCOUNT_NAME)
</select>
<select id="selectOurBankOptions" resultType="com.ruoyi.ccdi.project.domain.vo.CcdiBankStatementOptionVO">
SELECT DISTINCT
TRIM(bs.BANK) AS label,
TRIM(bs.BANK) AS value
FROM ccdi_bank_statement bs
WHERE bs.project_id = #{projectId}
AND bs.BANK IS NOT NULL
AND TRIM(bs.BANK) != ''
ORDER BY TRIM(bs.BANK)
</select>
<select id="selectOurAccountOptions" resultType="com.ruoyi.ccdi.project.domain.vo.CcdiBankStatementOptionVO">
SELECT DISTINCT
TRIM(bs.LE_ACCOUNT_NO) AS label,
TRIM(bs.LE_ACCOUNT_NO) AS value
FROM ccdi_bank_statement bs
WHERE bs.project_id = #{projectId}
AND bs.LE_ACCOUNT_NO IS NOT NULL
AND TRIM(bs.LE_ACCOUNT_NO) != ''
ORDER BY TRIM(bs.LE_ACCOUNT_NO)
</select>
<insert id="insertBatch" parameterType="java.util.List">
insert into ccdi_bank_statement (
project_id, LE_ID, ACCOUNT_ID, group_id,

View File

@@ -1,6 +1,9 @@
package com.ruoyi.ccdi.project.service.impl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.ccdi.project.domain.dto.CcdiBankStatementQueryDTO;
import com.ruoyi.ccdi.project.domain.vo.CcdiBankStatementFilterOptionsVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiBankStatementListVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiBankStatementOptionVO;
import com.ruoyi.ccdi.project.mapper.CcdiBankStatementMapper;
import org.junit.jupiter.api.Test;
@@ -12,6 +15,9 @@ import org.mockito.junit.jupiter.MockitoExtension;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
@@ -33,4 +39,17 @@ class CcdiBankStatementServiceImplTest {
assertEquals(1, result.getOurSubjectOptions().size());
}
@Test
void pageQuery_shouldNormalizeSortFieldAndDirection() {
Page<CcdiBankStatementListVO> page = new Page<>(1, 10);
CcdiBankStatementQueryDTO queryDTO = new CcdiBankStatementQueryDTO();
queryDTO.setProjectId(100L);
queryDTO.setOrderBy("amount");
queryDTO.setOrderDirection("desc");
service.selectStatementPage(page, queryDTO);
verify(bankStatementMapper).selectStatementPage(eq(page), same(queryDTO));
}
}