优化无外部人员涉疑交易查询
This commit is contained in:
@@ -22,4 +22,7 @@ public class CcdiProjectSuspiciousTransactionQueryDTO {
|
||||
|
||||
/** 每页数量 */
|
||||
private Integer pageSize;
|
||||
|
||||
/** 是否包含外部人员预警分支 */
|
||||
private Boolean includeExternalPerson;
|
||||
}
|
||||
|
||||
@@ -163,6 +163,14 @@ public interface CcdiProjectOverviewMapper {
|
||||
*/
|
||||
CcdiProjectExternalRiskSummaryVO selectExternalRiskSummaryByProjectId(@Param("projectId") Long projectId);
|
||||
|
||||
/**
|
||||
* 判断项目是否存在外部人员主体
|
||||
*
|
||||
* @param projectId 项目ID
|
||||
* @return 存在时返回1,否则返回空
|
||||
*/
|
||||
Integer selectExternalPersonSubjectExistsByProjectId(@Param("projectId") Long projectId);
|
||||
|
||||
/**
|
||||
* 查询外部人员预警模型卡片
|
||||
*
|
||||
|
||||
@@ -86,6 +86,12 @@ public class CcdiProjectOverviewServiceImpl implements ICcdiProjectOverviewServi
|
||||
|
||||
private static final String ACTION_LABEL = "查看详情";
|
||||
|
||||
private static final String SUSPICIOUS_TYPE_ALL = "ALL";
|
||||
|
||||
private static final String SUSPICIOUS_TYPE_MODEL_RULE = "MODEL_RULE";
|
||||
|
||||
private static final String SUSPICIOUS_TYPE_EXTERNAL_PERSON = "EXTERNAL_PERSON";
|
||||
|
||||
private static final String EXCLUSION_TYPE_STATEMENT = "STATEMENT";
|
||||
|
||||
private static final String EXCLUSION_TYPE_OBJECT = "OBJECT";
|
||||
@@ -369,6 +375,11 @@ public class CcdiProjectOverviewServiceImpl implements ICcdiProjectOverviewServi
|
||||
) {
|
||||
ensureProjectExists(queryDTO.getProjectId());
|
||||
normalizeSuspiciousTransactionQuery(queryDTO);
|
||||
prepareSuspiciousTransactionExternalBranch(queryDTO);
|
||||
|
||||
if (isExternalPersonOnlyWithoutSubject(queryDTO)) {
|
||||
return emptySuspiciousTransactionPage();
|
||||
}
|
||||
|
||||
Page<CcdiProjectSuspiciousTransactionItemVO> page = new Page<>(
|
||||
defaultPageNum(queryDTO.getPageNum()),
|
||||
@@ -389,6 +400,11 @@ public class CcdiProjectOverviewServiceImpl implements ICcdiProjectOverviewServi
|
||||
) {
|
||||
ensureProjectExists(queryDTO.getProjectId());
|
||||
normalizeSuspiciousTransactionQuery(queryDTO);
|
||||
prepareSuspiciousTransactionExternalBranch(queryDTO);
|
||||
|
||||
if (isExternalPersonOnlyWithoutSubject(queryDTO)) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
return defaultList(overviewMapper.selectReportSuspiciousTransactionList(queryDTO)).stream()
|
||||
.map(this::buildSuspiciousTransactionExcelRow)
|
||||
@@ -719,12 +735,42 @@ public class CcdiProjectOverviewServiceImpl implements ICcdiProjectOverviewServi
|
||||
queryDTO.setModelCode(null);
|
||||
}
|
||||
if (queryDTO.getSuspiciousType() == null || queryDTO.getSuspiciousType().isBlank()) {
|
||||
queryDTO.setSuspiciousType("ALL");
|
||||
queryDTO.setSuspiciousType(SUSPICIOUS_TYPE_ALL);
|
||||
return;
|
||||
}
|
||||
queryDTO.setSuspiciousType(queryDTO.getSuspiciousType().trim().toUpperCase());
|
||||
}
|
||||
|
||||
private void prepareSuspiciousTransactionExternalBranch(CcdiProjectSuspiciousTransactionQueryDTO queryDTO) {
|
||||
if (!shouldCheckExternalPersonBranch(queryDTO.getSuspiciousType())) {
|
||||
queryDTO.setIncludeExternalPerson(false);
|
||||
return;
|
||||
}
|
||||
queryDTO.setIncludeExternalPerson(hasExternalPersonSubject(queryDTO.getProjectId()));
|
||||
}
|
||||
|
||||
private boolean shouldCheckExternalPersonBranch(String suspiciousType) {
|
||||
return SUSPICIOUS_TYPE_ALL.equals(suspiciousType)
|
||||
|| SUSPICIOUS_TYPE_MODEL_RULE.equals(suspiciousType)
|
||||
|| SUSPICIOUS_TYPE_EXTERNAL_PERSON.equals(suspiciousType);
|
||||
}
|
||||
|
||||
private boolean hasExternalPersonSubject(Long projectId) {
|
||||
return overviewMapper.selectExternalPersonSubjectExistsByProjectId(projectId) != null;
|
||||
}
|
||||
|
||||
private boolean isExternalPersonOnlyWithoutSubject(CcdiProjectSuspiciousTransactionQueryDTO queryDTO) {
|
||||
return SUSPICIOUS_TYPE_EXTERNAL_PERSON.equals(queryDTO.getSuspiciousType())
|
||||
&& !Boolean.TRUE.equals(queryDTO.getIncludeExternalPerson());
|
||||
}
|
||||
|
||||
private CcdiProjectSuspiciousTransactionPageVO emptySuspiciousTransactionPage() {
|
||||
CcdiProjectSuspiciousTransactionPageVO result = new CcdiProjectSuspiciousTransactionPageVO();
|
||||
result.setRows(List.of());
|
||||
result.setTotal(0L);
|
||||
return result;
|
||||
}
|
||||
|
||||
private CcdiProjectOverviewStatVO buildStat(String key, String label, Integer value) {
|
||||
CcdiProjectOverviewStatVO stat = new CcdiProjectOverviewStatVO();
|
||||
stat.setKey(key);
|
||||
|
||||
@@ -811,6 +811,22 @@
|
||||
and risk.cert_no = subject.cert_no
|
||||
</select>
|
||||
|
||||
<select id="selectExternalPersonSubjectExistsByProjectId" resultType="java.lang.Integer">
|
||||
select 1
|
||||
from ccdi_bank_statement bs
|
||||
left join ccdi_base_staff staff
|
||||
on staff.id_card = bs.cret_no
|
||||
left join ccdi_staff_fmy_relation relation
|
||||
on relation.status = 1
|
||||
and relation.relation_cert_no = bs.cret_no
|
||||
where bs.project_id = #{projectId}
|
||||
and bs.cret_no is not null
|
||||
and trim(bs.cret_no) != ''
|
||||
and staff.id_card is null
|
||||
and relation.relation_cert_no is null
|
||||
limit 1
|
||||
</select>
|
||||
|
||||
<select id="selectExternalRiskModelCardsByProjectId" resultType="com.ruoyi.ccdi.project.domain.vo.CcdiProjectRiskModelCardVO">
|
||||
<bind name="externalProjectId" value="projectId"/>
|
||||
select
|
||||
@@ -1161,26 +1177,28 @@
|
||||
<include refid="suspiciousTransactionNameHitSql"/>
|
||||
) name_hits on name_hits.bankStatementId = base.bankStatementId
|
||||
|
||||
union all
|
||||
<if test="query.includeExternalPerson == true">
|
||||
union all
|
||||
|
||||
select
|
||||
external_hits.bankStatementId,
|
||||
external_hits.trxDate,
|
||||
external_hits.relatedPersonName,
|
||||
external_hits.relatedStaffName,
|
||||
external_hits.relatedStaffCode,
|
||||
external_hits.relationType,
|
||||
external_hits.userMemo,
|
||||
external_hits.cashType,
|
||||
external_hits.displayAmount,
|
||||
external_hits.hasModelRuleHit,
|
||||
external_hits.hasNameListHit,
|
||||
external_hits.suspiciousPersonName,
|
||||
external_hits.matchPriority,
|
||||
external_hits.nameListHitType
|
||||
from (
|
||||
<include refid="externalSuspiciousTransactionSql"/>
|
||||
) external_hits
|
||||
select
|
||||
external_hits.bankStatementId,
|
||||
external_hits.trxDate,
|
||||
external_hits.relatedPersonName,
|
||||
external_hits.relatedStaffName,
|
||||
external_hits.relatedStaffCode,
|
||||
external_hits.relationType,
|
||||
external_hits.userMemo,
|
||||
external_hits.cashType,
|
||||
external_hits.displayAmount,
|
||||
external_hits.hasModelRuleHit,
|
||||
external_hits.hasNameListHit,
|
||||
external_hits.suspiciousPersonName,
|
||||
external_hits.matchPriority,
|
||||
external_hits.nameListHitType
|
||||
from (
|
||||
<include refid="externalSuspiciousTransactionSql"/>
|
||||
) external_hits
|
||||
</if>
|
||||
</sql>
|
||||
|
||||
<sql id="suspiciousTransactionAggregatedSql">
|
||||
|
||||
@@ -91,7 +91,9 @@ class CcdiProjectOverviewMapperSqlTest {
|
||||
String xml = Files.readString(Path.of("src/main/resources/mapper/ccdi/project/CcdiProjectOverviewMapper.xml"));
|
||||
String suspiciousSql = extractSelect(xml, "selectSuspiciousTransactionPage");
|
||||
String modelHitSql = extractSqlFragment(xml, "suspiciousTransactionModelHitSql");
|
||||
String mergedSql = extractSqlFragment(xml, "suspiciousTransactionMergedSql");
|
||||
String aggregatedSql = extractSqlFragment(xml, "suspiciousTransactionAggregatedSql");
|
||||
String externalSubjectExistsSql = extractSelect(xml, "selectExternalPersonSubjectExistsByProjectId");
|
||||
|
||||
assertTrue(modelHitSql.contains("from ccdi_bank_statement_tag_result tr"), modelHitSql);
|
||||
assertTrue(modelHitSql.contains("tr.bank_statement_id is not null"), modelHitSql);
|
||||
@@ -104,6 +106,11 @@ class CcdiProjectOverviewMapperSqlTest {
|
||||
assertTrue(suspiciousSql.contains("hasModelRuleHit"), suspiciousSql);
|
||||
assertTrue(suspiciousSql.contains("hasNameListHit"), suspiciousSql);
|
||||
assertTrue(suspiciousSql.contains("final_result.nameListHitType"), suspiciousSql);
|
||||
assertTrue(mergedSql.contains("<if test=\"query.includeExternalPerson == true\">"), mergedSql);
|
||||
assertTrue(mergedSql.contains("<include refid=\"externalSuspiciousTransactionSql\"/>"), mergedSql);
|
||||
assertTrue(externalSubjectExistsSql.contains("limit 1"), externalSubjectExistsSql);
|
||||
assertTrue(externalSubjectExistsSql.contains("staff.id_card is null"), externalSubjectExistsSql);
|
||||
assertTrue(externalSubjectExistsSql.contains("relation.relation_cert_no is null"), externalSubjectExistsSql);
|
||||
|
||||
String reportSuspiciousSql = extractSelect(xml, "selectReportSuspiciousTransactionList");
|
||||
assertTrue(reportSuspiciousSql.contains("final_result.nameListHitType = '中介'"), reportSuspiciousSql);
|
||||
|
||||
@@ -26,6 +26,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@@ -93,6 +94,70 @@ class CcdiProjectOverviewServiceSuspiciousTransactionTest {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldIncludeExternalBranchWhenExternalSubjectExistsForAllSuspiciousTransactions() {
|
||||
CcdiProject project = new CcdiProject();
|
||||
project.setProjectId(40L);
|
||||
when(projectMapper.selectById(40L)).thenReturn(project);
|
||||
when(overviewMapper.selectExternalPersonSubjectExistsByProjectId(40L)).thenReturn(1);
|
||||
|
||||
Page<CcdiProjectSuspiciousTransactionItemVO> page = new Page<>(1, 10);
|
||||
page.setRecords(List.of());
|
||||
page.setTotal(0);
|
||||
when(overviewMapper.selectSuspiciousTransactionPage(any(Page.class), any(CcdiProjectSuspiciousTransactionQueryDTO.class)))
|
||||
.thenReturn(page);
|
||||
|
||||
CcdiProjectSuspiciousTransactionQueryDTO queryDTO = new CcdiProjectSuspiciousTransactionQueryDTO();
|
||||
queryDTO.setProjectId(40L);
|
||||
|
||||
CcdiProjectSuspiciousTransactionPageVO result = service.getSuspiciousTransactions(queryDTO);
|
||||
|
||||
assertEquals(0L, result.getTotal());
|
||||
verify(overviewMapper).selectSuspiciousTransactionPage(
|
||||
any(Page.class),
|
||||
argThat(query -> "ALL".equals(query.getSuspiciousType())
|
||||
&& Boolean.TRUE.equals(query.getIncludeExternalPerson()))
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnEmptyExternalSuspiciousTransactionsWhenExternalSubjectDoesNotExist() {
|
||||
CcdiProject project = new CcdiProject();
|
||||
project.setProjectId(40L);
|
||||
when(projectMapper.selectById(40L)).thenReturn(project);
|
||||
when(overviewMapper.selectExternalPersonSubjectExistsByProjectId(40L)).thenReturn(null);
|
||||
|
||||
CcdiProjectSuspiciousTransactionQueryDTO queryDTO = new CcdiProjectSuspiciousTransactionQueryDTO();
|
||||
queryDTO.setProjectId(40L);
|
||||
queryDTO.setSuspiciousType("external_person");
|
||||
|
||||
CcdiProjectSuspiciousTransactionPageVO result = service.getSuspiciousTransactions(queryDTO);
|
||||
|
||||
assertEquals(0L, result.getTotal());
|
||||
assertTrue(result.getRows().isEmpty());
|
||||
verify(overviewMapper, never()).selectSuspiciousTransactionPage(
|
||||
any(Page.class),
|
||||
any(CcdiProjectSuspiciousTransactionQueryDTO.class)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnEmptyExternalSuspiciousTransactionExportWhenExternalSubjectDoesNotExist() {
|
||||
CcdiProject project = new CcdiProject();
|
||||
project.setProjectId(40L);
|
||||
when(projectMapper.selectById(40L)).thenReturn(project);
|
||||
when(overviewMapper.selectExternalPersonSubjectExistsByProjectId(40L)).thenReturn(null);
|
||||
|
||||
CcdiProjectSuspiciousTransactionQueryDTO queryDTO = new CcdiProjectSuspiciousTransactionQueryDTO();
|
||||
queryDTO.setProjectId(40L);
|
||||
queryDTO.setSuspiciousType("EXTERNAL_PERSON");
|
||||
|
||||
List<CcdiProjectSuspiciousTransactionExcel> rows = service.exportSuspiciousTransactions(queryDTO);
|
||||
|
||||
assertTrue(rows.isEmpty());
|
||||
verify(overviewMapper, never()).selectReportSuspiciousTransactionList(any(CcdiProjectSuspiciousTransactionQueryDTO.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldExportSuspiciousTransactionsWithCurrentFilter() {
|
||||
CcdiProject project = new CcdiProject();
|
||||
|
||||
Reference in New Issue
Block a user