实现第二期对象聚合规则真实SQL
This commit is contained in:
@@ -110,9 +110,13 @@ public interface CcdiBankTagAnalysisMapper {
|
|||||||
* 疑似赌博交易
|
* 疑似赌博交易
|
||||||
*
|
*
|
||||||
* @param projectId 项目ID
|
* @param projectId 项目ID
|
||||||
|
* @param amountMinThreshold 可疑金额下限
|
||||||
|
* @param amountMaxThreshold 可疑金额上限
|
||||||
* @return 对象命中结果
|
* @return 对象命中结果
|
||||||
*/
|
*/
|
||||||
List<BankTagObjectHitVO> selectMultiPartyGamblingTransferObjects(@Param("projectId") Long projectId);
|
List<BankTagObjectHitVO> selectMultiPartyGamblingTransferObjects(@Param("projectId") Long projectId,
|
||||||
|
@Param("amountMinThreshold") BigDecimal amountMinThreshold,
|
||||||
|
@Param("amountMaxThreshold") BigDecimal amountMaxThreshold);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 疑似敏感交易
|
* 疑似敏感交易
|
||||||
@@ -134,17 +138,23 @@ public interface CcdiBankTagAnalysisMapper {
|
|||||||
* 月度固定收入疑似兼职
|
* 月度固定收入疑似兼职
|
||||||
*
|
*
|
||||||
* @param projectId 项目ID
|
* @param projectId 项目ID
|
||||||
|
* @param threshold 月度固定收入阈值
|
||||||
* @return 对象命中结果
|
* @return 对象命中结果
|
||||||
*/
|
*/
|
||||||
List<BankTagObjectHitVO> selectMonthlyFixedIncomeObjects(@Param("projectId") Long projectId);
|
List<BankTagObjectHitVO> selectMonthlyFixedIncomeObjects(@Param("projectId") Long projectId,
|
||||||
|
@Param("threshold") BigDecimal threshold);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 固定交易对手转入疑似兼职
|
* 固定交易对手转入疑似兼职
|
||||||
*
|
*
|
||||||
* @param projectId 项目ID
|
* @param projectId 项目ID
|
||||||
|
* @param quarterMinThreshold 季度收入下限
|
||||||
|
* @param quarterMaxThreshold 季度收入上限
|
||||||
* @return 对象命中结果
|
* @return 对象命中结果
|
||||||
*/
|
*/
|
||||||
List<BankTagObjectHitVO> selectFixedCounterpartyTransferObjects(@Param("projectId") Long projectId);
|
List<BankTagObjectHitVO> selectFixedCounterpartyTransferObjects(@Param("projectId") Long projectId,
|
||||||
|
@Param("quarterMinThreshold") BigDecimal quarterMinThreshold,
|
||||||
|
@Param("quarterMaxThreshold") BigDecimal quarterMaxThreshold);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 摘要收入疑似兼职
|
* 摘要收入疑似兼职
|
||||||
|
|||||||
@@ -267,9 +267,19 @@ public class CcdiBankTagServiceImpl implements ICcdiBankTagService {
|
|||||||
toInteger(config.getThresholdValue("FREQUENT_CASH_DEPOSIT"))
|
toInteger(config.getThresholdValue("FREQUENT_CASH_DEPOSIT"))
|
||||||
);
|
);
|
||||||
case "LOW_INCOME_RELATIVE_LARGE_TRANSACTION" -> analysisMapper.selectLowIncomeRelativeLargeTransactionObjects(projectId);
|
case "LOW_INCOME_RELATIVE_LARGE_TRANSACTION" -> analysisMapper.selectLowIncomeRelativeLargeTransactionObjects(projectId);
|
||||||
case "MULTI_PARTY_GAMBLING_TRANSFER" -> analysisMapper.selectMultiPartyGamblingTransferObjects(projectId);
|
case "MULTI_PARTY_GAMBLING_TRANSFER" -> analysisMapper.selectMultiPartyGamblingTransferObjects(
|
||||||
case "MONTHLY_FIXED_INCOME" -> analysisMapper.selectMonthlyFixedIncomeObjects(projectId);
|
projectId,
|
||||||
case "FIXED_COUNTERPARTY_TRANSFER" -> analysisMapper.selectFixedCounterpartyTransferObjects(projectId);
|
toBigDecimal(config.getThresholdValue("MULTI_PARTY_AMT_MIN")),
|
||||||
|
toBigDecimal(config.getThresholdValue("MULTI_PARTY_AMT_MAX"))
|
||||||
|
);
|
||||||
|
case "MONTHLY_FIXED_INCOME" -> analysisMapper.selectMonthlyFixedIncomeObjects(
|
||||||
|
projectId, toBigDecimal(config.getThresholdValue("MONTHLY_FIXED_INCOME"))
|
||||||
|
);
|
||||||
|
case "FIXED_COUNTERPARTY_TRANSFER" -> analysisMapper.selectFixedCounterpartyTransferObjects(
|
||||||
|
projectId,
|
||||||
|
toBigDecimal(config.getThresholdValue("FIXED_COUNTERPARTY_TRANSFER_MIN")),
|
||||||
|
toBigDecimal(config.getThresholdValue("FIXED_COUNTERPARTY_TRANSFER_MAX"))
|
||||||
|
);
|
||||||
case "INTEREST_PAYMENT_BY_OTHERS" -> analysisMapper.selectInterestPaymentByOthersObjects(projectId);
|
case "INTEREST_PAYMENT_BY_OTHERS" -> analysisMapper.selectInterestPaymentByOthersObjects(projectId);
|
||||||
case "SUPPLIER_CONCENTRATION" -> analysisMapper.selectSupplierConcentrationObjects(projectId);
|
case "SUPPLIER_CONCENTRATION" -> analysisMapper.selectSupplierConcentrationObjects(projectId);
|
||||||
case "WITHDRAW_CNT" -> analysisMapper.selectWithdrawCntObjects(
|
case "WITHDRAW_CNT" -> analysisMapper.selectWithdrawCntObjects(
|
||||||
|
|||||||
@@ -124,6 +124,22 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
)
|
)
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
|
<sql id="salaryIncomePredicate">
|
||||||
|
bs.CUSTOMER_ACCOUNT_NAME = '浙江兰溪农村商业银行股份有限公司'
|
||||||
|
and (
|
||||||
|
IFNULL(bs.USER_MEMO, '') REGEXP '代发|工资|奖金|薪酬|薪金|补贴|薪|年终奖|年金|加班费|劳务费|劳务外包|提成|劳务派遣|绩效|酬劳|PAYROLL|SALA|CPF|directors.*fees'
|
||||||
|
or IFNULL(bs.CASH_TYPE, '') REGEXP '代发|工资|劳务费'
|
||||||
|
)
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<sql id="salaryDeductionPredicate">
|
||||||
|
(
|
||||||
|
IFNULL(bs.USER_MEMO, '') REGEXP '代扣|个税|社保|公积金|水费|电费|燃气|话费|党费|医保'
|
||||||
|
or IFNULL(bs.CASH_TYPE, '') REGEXP '代扣|个税|社保|公积金'
|
||||||
|
or IFNULL(bs.CUSTOMER_ACCOUNT_NAME, '') REGEXP '税务|社保|公积金'
|
||||||
|
)
|
||||||
|
</sql>
|
||||||
|
|
||||||
<select id="selectHouseOrCarExpenseStatements" resultMap="BankTagStatementHitResultMap">
|
<select id="selectHouseOrCarExpenseStatements" resultMap="BankTagStatementHitResultMap">
|
||||||
select
|
select
|
||||||
bs.bank_statement_id AS bankStatementId,
|
bs.bank_statement_id AS bankStatementId,
|
||||||
@@ -376,19 +392,89 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<select id="selectLowIncomeRelativeLargeTransactionObjects" resultMap="BankTagObjectHitResultMap">
|
<select id="selectLowIncomeRelativeLargeTransactionObjects" resultMap="BankTagObjectHitResultMap">
|
||||||
select
|
select
|
||||||
'STAFF_ID_CARD' AS objectType,
|
'STAFF_ID_CARD' AS objectType,
|
||||||
'' AS objectKey,
|
t.objectKey AS objectKey,
|
||||||
'占位SQL,待补充真实规则' AS reasonDetail
|
CONCAT(
|
||||||
from ccdi_bank_statement bs
|
'低收入关系人累计交易 ', CAST(t.totalAmount AS CHAR),
|
||||||
where 1 = 0
|
' 元,命中关系人数 ', CAST(t.relationCount AS CHAR), ' 人'
|
||||||
|
) AS reasonDetail
|
||||||
|
from (
|
||||||
|
select
|
||||||
|
relation.person_id AS objectKey,
|
||||||
|
ROUND(SUM(IFNULL(bs.AMOUNT_DR, 0) + IFNULL(bs.AMOUNT_CR, 0)), 2) AS totalAmount,
|
||||||
|
COUNT(DISTINCT relation.relation_cert_no) AS relationCount
|
||||||
|
from ccdi_staff_fmy_relation relation
|
||||||
|
inner join ccdi_bank_statement bs on relation.relation_cert_no = bs.cret_no
|
||||||
|
where relation.status = 1
|
||||||
|
and (
|
||||||
|
relation.annual_income is null
|
||||||
|
or relation.annual_income = 0
|
||||||
|
or relation.annual_income / 12 < 3000
|
||||||
|
)
|
||||||
|
and bs.project_id = #{projectId}
|
||||||
|
and IFNULL(bs.LE_ACCOUNT_NAME, '') <> IFNULL(bs.CUSTOMER_ACCOUNT_NAME, '')
|
||||||
|
group by relation.person_id
|
||||||
|
having SUM(IFNULL(bs.AMOUNT_DR, 0) + IFNULL(bs.AMOUNT_CR, 0)) > 100000
|
||||||
|
) t
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectMultiPartyGamblingTransferObjects" resultMap="BankTagObjectHitResultMap">
|
<select id="selectMultiPartyGamblingTransferObjects" resultMap="BankTagObjectHitResultMap">
|
||||||
select
|
select
|
||||||
'STAFF_ID_CARD' AS objectType,
|
'STAFF_ID_CARD' AS objectType,
|
||||||
'' AS objectKey,
|
t.objectKey AS objectKey,
|
||||||
'占位SQL,待补充真实规则' AS reasonDetail
|
CONCAT(
|
||||||
from ccdi_bank_statement bs
|
'交易日 ', MAX(t.tradeDate),
|
||||||
where 1 = 0
|
' 发生 ', CAST(MAX(t.hitCount) AS CHAR),
|
||||||
|
' 笔疑似赌博交易,涉及 ', CAST(MAX(t.partyCount) AS CHAR),
|
||||||
|
' 个对手方,金额合计 ', CAST(MAX(t.totalAmount) AS CHAR), ' 元'
|
||||||
|
) AS reasonDetail
|
||||||
|
from (
|
||||||
|
select
|
||||||
|
source.objectKey AS objectKey,
|
||||||
|
source.tradeDate AS tradeDate,
|
||||||
|
COUNT(1) AS hitCount,
|
||||||
|
COUNT(DISTINCT source.customerAccountName) AS partyCount,
|
||||||
|
ROUND(SUM(source.tradeAmount), 2) AS totalAmount
|
||||||
|
from (
|
||||||
|
select
|
||||||
|
staff.id_card AS objectKey,
|
||||||
|
LEFT(TRIM(bs.TRX_DATE), 10) AS tradeDate,
|
||||||
|
bs.CUSTOMER_ACCOUNT_NAME AS customerAccountName,
|
||||||
|
GREATEST(IFNULL(bs.AMOUNT_DR, 0), IFNULL(bs.AMOUNT_CR, 0)) AS tradeAmount
|
||||||
|
from ccdi_bank_statement bs
|
||||||
|
inner join ccdi_base_staff staff on staff.id_card = bs.cret_no
|
||||||
|
where bs.project_id = #{projectId}
|
||||||
|
and GREATEST(IFNULL(bs.AMOUNT_DR, 0), IFNULL(bs.AMOUNT_CR, 0)) between #{amountMinThreshold} and #{amountMaxThreshold}
|
||||||
|
and IFNULL(bs.CUSTOMER_ACCOUNT_NAME, '') <> ''
|
||||||
|
and (
|
||||||
|
IFNULL(bs.USER_MEMO, '') REGEXP '微信|wechat|WeChat|财付通|Tenpay|支付宝|Alipay|转账|红包'
|
||||||
|
or IFNULL(bs.CASH_TYPE, '') REGEXP '微信|wechat|WeChat|财付通|Tenpay|支付宝|Alipay|转账|红包'
|
||||||
|
or IFNULL(bs.CUSTOMER_ACCOUNT_NAME, '') REGEXP '微信|wechat|WeChat|财付通|Tenpay|支付宝|Alipay'
|
||||||
|
)
|
||||||
|
|
||||||
|
union all
|
||||||
|
|
||||||
|
select
|
||||||
|
relation.person_id AS objectKey,
|
||||||
|
LEFT(TRIM(bs.TRX_DATE), 10) AS tradeDate,
|
||||||
|
bs.CUSTOMER_ACCOUNT_NAME AS customerAccountName,
|
||||||
|
GREATEST(IFNULL(bs.AMOUNT_DR, 0), IFNULL(bs.AMOUNT_CR, 0)) AS tradeAmount
|
||||||
|
from ccdi_bank_statement bs
|
||||||
|
inner join ccdi_staff_fmy_relation relation on relation.relation_cert_no = bs.cret_no
|
||||||
|
where relation.status = 1
|
||||||
|
and bs.project_id = #{projectId}
|
||||||
|
and GREATEST(IFNULL(bs.AMOUNT_DR, 0), IFNULL(bs.AMOUNT_CR, 0)) between #{amountMinThreshold} and #{amountMaxThreshold}
|
||||||
|
and IFNULL(bs.CUSTOMER_ACCOUNT_NAME, '') <> ''
|
||||||
|
and (
|
||||||
|
IFNULL(bs.USER_MEMO, '') REGEXP '微信|wechat|WeChat|财付通|Tenpay|支付宝|Alipay|转账|红包'
|
||||||
|
or IFNULL(bs.CASH_TYPE, '') REGEXP '微信|wechat|WeChat|财付通|Tenpay|支付宝|Alipay|转账|红包'
|
||||||
|
or IFNULL(bs.CUSTOMER_ACCOUNT_NAME, '') REGEXP '微信|wechat|WeChat|财付通|Tenpay|支付宝|Alipay'
|
||||||
|
)
|
||||||
|
) source
|
||||||
|
group by source.objectKey, source.tradeDate
|
||||||
|
having COUNT(1) > 2
|
||||||
|
and COUNT(DISTINCT source.customerAccountName) >= 2
|
||||||
|
) t
|
||||||
|
group by t.objectKey
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectGamblingSensitiveKeywordStatements" resultMap="BankTagStatementHitResultMap">
|
<select id="selectGamblingSensitiveKeywordStatements" resultMap="BankTagStatementHitResultMap">
|
||||||
@@ -440,19 +526,110 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<select id="selectMonthlyFixedIncomeObjects" resultMap="BankTagObjectHitResultMap">
|
<select id="selectMonthlyFixedIncomeObjects" resultMap="BankTagObjectHitResultMap">
|
||||||
select
|
select
|
||||||
'STAFF_ID_CARD' AS objectType,
|
'STAFF_ID_CARD' AS objectType,
|
||||||
'' AS objectKey,
|
t.objectKey AS objectKey,
|
||||||
'占位SQL,待补充真实规则' AS reasonDetail
|
CONCAT(
|
||||||
from ccdi_bank_statement bs
|
'近12个月有 ', CAST(t.monthCount AS CHAR),
|
||||||
where 1 = 0
|
' 个月固定收入超过阈值,月均收入 ', CAST(t.avgAmount AS CHAR), ' 元'
|
||||||
|
) AS reasonDetail
|
||||||
|
from (
|
||||||
|
select
|
||||||
|
monthly_income.idCard AS objectKey,
|
||||||
|
COUNT(DISTINCT monthly_income.incomeMonth) AS monthCount,
|
||||||
|
ROUND(AVG(monthly_income.monthAmount), 2) AS avgAmount
|
||||||
|
from (
|
||||||
|
select
|
||||||
|
staff.id_card AS idCard,
|
||||||
|
LEFT(TRIM(bs.TRX_DATE), 7) AS incomeMonth,
|
||||||
|
ROUND(SUM(IFNULL(bs.AMOUNT_CR, 0)), 2) AS monthAmount
|
||||||
|
from ccdi_bank_statement bs
|
||||||
|
inner join ccdi_base_staff staff on staff.id_card = bs.cret_no
|
||||||
|
where bs.project_id = #{projectId}
|
||||||
|
and IFNULL(bs.AMOUNT_CR, 0) > 0
|
||||||
|
and IFNULL(bs.CUSTOMER_ACCOUNT_NAME, '') <> ''
|
||||||
|
and IFNULL(bs.LE_ACCOUNT_NAME, '') <> IFNULL(bs.CUSTOMER_ACCOUNT_NAME, '')
|
||||||
|
and <include refid="salaryExclusionPredicate"/>
|
||||||
|
and COALESCE(
|
||||||
|
STR_TO_DATE(LEFT(TRIM(bs.TRX_DATE), 19), '%Y-%m-%d %H:%i:%s'),
|
||||||
|
STR_TO_DATE(LEFT(TRIM(bs.TRX_DATE), 10), '%Y-%m-%d')
|
||||||
|
) >= DATE_SUB(CURDATE(), INTERVAL 12 MONTH)
|
||||||
|
group by staff.id_card, LEFT(TRIM(bs.TRX_DATE), 7)
|
||||||
|
having SUM(IFNULL(bs.AMOUNT_CR, 0)) > #{threshold}
|
||||||
|
) monthly_income
|
||||||
|
group by monthly_income.idCard
|
||||||
|
having COUNT(DISTINCT monthly_income.incomeMonth) >= 6
|
||||||
|
and STDDEV(monthly_income.monthAmount) / NULLIF(AVG(monthly_income.monthAmount), 0) <= 0.3
|
||||||
|
) t
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectFixedCounterpartyTransferObjects" resultMap="BankTagObjectHitResultMap">
|
<select id="selectFixedCounterpartyTransferObjects" resultMap="BankTagObjectHitResultMap">
|
||||||
select
|
select
|
||||||
'STAFF_ID_CARD' AS objectType,
|
'STAFF_ID_CARD' AS objectType,
|
||||||
'' AS objectKey,
|
t.objectKey AS objectKey,
|
||||||
'占位SQL,待补充真实规则' AS reasonDetail
|
CONCAT(
|
||||||
from ccdi_bank_statement bs
|
'固定对手“', t.customerAccountNames,
|
||||||
where 1 = 0
|
'”在 ', CAST(t.quarterCount AS CHAR),
|
||||||
|
' 个季度累计转入位于区间 [', CAST(#{quarterMinThreshold} AS CHAR),
|
||||||
|
', ', CAST(#{quarterMaxThreshold} AS CHAR), '] 元'
|
||||||
|
) AS reasonDetail
|
||||||
|
from (
|
||||||
|
select
|
||||||
|
stable_income.idCard AS objectKey,
|
||||||
|
GROUP_CONCAT(DISTINCT stable_income.customerAccountName ORDER BY stable_income.customerAccountName SEPARATOR '、') AS customerAccountNames,
|
||||||
|
MAX(stable_income.quarterCount) AS quarterCount
|
||||||
|
from (
|
||||||
|
select
|
||||||
|
quarter_income.idCard AS idCard,
|
||||||
|
quarter_income.customerAccountName AS customerAccountName,
|
||||||
|
COUNT(DISTINCT quarter_income.transQuarter) AS quarterCount
|
||||||
|
from (
|
||||||
|
select
|
||||||
|
staff.id_card AS idCard,
|
||||||
|
bs.CUSTOMER_ACCOUNT_NAME AS customerAccountName,
|
||||||
|
CONCAT(
|
||||||
|
YEAR(COALESCE(
|
||||||
|
STR_TO_DATE(LEFT(TRIM(bs.TRX_DATE), 19), '%Y-%m-%d %H:%i:%s'),
|
||||||
|
STR_TO_DATE(LEFT(TRIM(bs.TRX_DATE), 10), '%Y-%m-%d')
|
||||||
|
)),
|
||||||
|
'-Q',
|
||||||
|
QUARTER(COALESCE(
|
||||||
|
STR_TO_DATE(LEFT(TRIM(bs.TRX_DATE), 19), '%Y-%m-%d %H:%i:%s'),
|
||||||
|
STR_TO_DATE(LEFT(TRIM(bs.TRX_DATE), 10), '%Y-%m-%d')
|
||||||
|
))
|
||||||
|
) AS transQuarter,
|
||||||
|
ROUND(SUM(IFNULL(bs.AMOUNT_CR, 0)), 2) AS quarterAmount
|
||||||
|
from ccdi_bank_statement bs
|
||||||
|
inner join ccdi_base_staff staff on staff.id_card = bs.cret_no
|
||||||
|
where bs.project_id = #{projectId}
|
||||||
|
and IFNULL(bs.AMOUNT_CR, 0) > 0
|
||||||
|
and IFNULL(bs.CUSTOMER_ACCOUNT_NAME, '') <> ''
|
||||||
|
and IFNULL(bs.LE_ACCOUNT_NAME, '') <> IFNULL(bs.CUSTOMER_ACCOUNT_NAME, '')
|
||||||
|
and <include refid="salaryExclusionPredicate"/>
|
||||||
|
and COALESCE(
|
||||||
|
STR_TO_DATE(LEFT(TRIM(bs.TRX_DATE), 19), '%Y-%m-%d %H:%i:%s'),
|
||||||
|
STR_TO_DATE(LEFT(TRIM(bs.TRX_DATE), 10), '%Y-%m-%d')
|
||||||
|
) >= DATE_SUB(CURDATE(), INTERVAL 12 MONTH)
|
||||||
|
group by
|
||||||
|
staff.id_card,
|
||||||
|
bs.CUSTOMER_ACCOUNT_NAME,
|
||||||
|
CONCAT(
|
||||||
|
YEAR(COALESCE(
|
||||||
|
STR_TO_DATE(LEFT(TRIM(bs.TRX_DATE), 19), '%Y-%m-%d %H:%i:%s'),
|
||||||
|
STR_TO_DATE(LEFT(TRIM(bs.TRX_DATE), 10), '%Y-%m-%d')
|
||||||
|
)),
|
||||||
|
'-Q',
|
||||||
|
QUARTER(COALESCE(
|
||||||
|
STR_TO_DATE(LEFT(TRIM(bs.TRX_DATE), 19), '%Y-%m-%d %H:%i:%s'),
|
||||||
|
STR_TO_DATE(LEFT(TRIM(bs.TRX_DATE), 10), '%Y-%m-%d')
|
||||||
|
))
|
||||||
|
)
|
||||||
|
having SUM(IFNULL(bs.AMOUNT_CR, 0)) between #{quarterMinThreshold} and #{quarterMaxThreshold}
|
||||||
|
) quarter_income
|
||||||
|
group by quarter_income.idCard, quarter_income.customerAccountName
|
||||||
|
having COUNT(DISTINCT quarter_income.transQuarter) >= 2
|
||||||
|
) stable_income
|
||||||
|
group by stable_income.idCard
|
||||||
|
having COUNT(DISTINCT stable_income.customerAccountName) < 3
|
||||||
|
) t
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectSuspiciousIncomeKeywordStatements" resultMap="BankTagStatementHitResultMap">
|
<select id="selectSuspiciousIncomeKeywordStatements" resultMap="BankTagStatementHitResultMap">
|
||||||
@@ -754,10 +931,84 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<select id="selectSupplierConcentrationObjects" resultMap="BankTagObjectHitResultMap">
|
<select id="selectSupplierConcentrationObjects" resultMap="BankTagObjectHitResultMap">
|
||||||
select
|
select
|
||||||
'STAFF_ID_CARD' AS objectType,
|
'STAFF_ID_CARD' AS objectType,
|
||||||
'' AS objectKey,
|
t.objectKey AS objectKey,
|
||||||
'占位SQL,待补充真实规则' AS reasonDetail
|
CONCAT(
|
||||||
from ccdi_bank_statement bs
|
'供应商“', t.supplierName,
|
||||||
where 1 = 0
|
'”采购金额 ', CAST(t.supplierAmount AS CHAR),
|
||||||
|
' 元,占总采购金额 ', CAST(t.supplierRatioPct AS CHAR), '%'
|
||||||
|
) AS reasonDetail
|
||||||
|
from (
|
||||||
|
select
|
||||||
|
supplier_hit.objectKey AS objectKey,
|
||||||
|
SUBSTRING_INDEX(
|
||||||
|
GROUP_CONCAT(supplier_hit.supplierName ORDER BY supplier_hit.supplierRatio DESC SEPARATOR ','),
|
||||||
|
',',
|
||||||
|
1
|
||||||
|
) AS supplierName,
|
||||||
|
MAX(supplier_hit.supplierAmount) AS supplierAmount,
|
||||||
|
ROUND(MAX(supplier_hit.supplierRatio) * 100, 2) AS supplierRatioPct
|
||||||
|
from (
|
||||||
|
select
|
||||||
|
source.objectKey AS objectKey,
|
||||||
|
source.supplierName AS supplierName,
|
||||||
|
ROUND(SUM(source.actualAmount), 2) AS supplierAmount,
|
||||||
|
SUM(source.actualAmount) / NULLIF(total_amount.totalAmount, 0) AS supplierRatio
|
||||||
|
from (
|
||||||
|
select distinct
|
||||||
|
staff.id_card AS objectKey,
|
||||||
|
pt.purchase_id AS purchaseId,
|
||||||
|
pt.supplier_name AS supplierName,
|
||||||
|
IFNULL(pt.actual_amount, 0) AS actualAmount
|
||||||
|
from ccdi_purchase_transaction pt
|
||||||
|
inner join ccdi_base_staff staff on CAST(staff.staff_id AS CHAR) = pt.applicant_id
|
||||||
|
where IFNULL(pt.actual_amount, 0) > 0
|
||||||
|
and IFNULL(pt.supplier_name, '') <> ''
|
||||||
|
|
||||||
|
union
|
||||||
|
|
||||||
|
select distinct
|
||||||
|
staff.id_card AS objectKey,
|
||||||
|
pt.purchase_id AS purchaseId,
|
||||||
|
pt.supplier_name AS supplierName,
|
||||||
|
IFNULL(pt.actual_amount, 0) AS actualAmount
|
||||||
|
from ccdi_purchase_transaction pt
|
||||||
|
inner join ccdi_base_staff staff on CAST(staff.staff_id AS CHAR) = pt.purchase_leader_id
|
||||||
|
where pt.purchase_leader_id is not null
|
||||||
|
and IFNULL(pt.actual_amount, 0) > 0
|
||||||
|
and IFNULL(pt.supplier_name, '') <> ''
|
||||||
|
) source
|
||||||
|
inner join (
|
||||||
|
select
|
||||||
|
source_total.objectKey AS objectKey,
|
||||||
|
ROUND(SUM(source_total.actualAmount), 2) AS totalAmount
|
||||||
|
from (
|
||||||
|
select distinct
|
||||||
|
staff.id_card AS objectKey,
|
||||||
|
pt.purchase_id AS purchaseId,
|
||||||
|
IFNULL(pt.actual_amount, 0) AS actualAmount
|
||||||
|
from ccdi_purchase_transaction pt
|
||||||
|
inner join ccdi_base_staff staff on CAST(staff.staff_id AS CHAR) = pt.applicant_id
|
||||||
|
where IFNULL(pt.actual_amount, 0) > 0
|
||||||
|
|
||||||
|
union
|
||||||
|
|
||||||
|
select distinct
|
||||||
|
staff.id_card AS objectKey,
|
||||||
|
pt.purchase_id AS purchaseId,
|
||||||
|
IFNULL(pt.actual_amount, 0) AS actualAmount
|
||||||
|
from ccdi_purchase_transaction pt
|
||||||
|
inner join ccdi_base_staff staff on CAST(staff.staff_id AS CHAR) = pt.purchase_leader_id
|
||||||
|
where pt.purchase_leader_id is not null
|
||||||
|
and IFNULL(pt.actual_amount, 0) > 0
|
||||||
|
) source_total
|
||||||
|
group by source_total.objectKey
|
||||||
|
) total_amount
|
||||||
|
on total_amount.objectKey = source.objectKey
|
||||||
|
group by source.objectKey, source.supplierName, total_amount.totalAmount
|
||||||
|
having SUM(source.actualAmount) / NULLIF(total_amount.totalAmount, 0) > 0.7
|
||||||
|
) supplier_hit
|
||||||
|
group by supplier_hit.objectKey
|
||||||
|
) t
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectStockTfrLargeStatements" resultMap="BankTagStatementHitResultMap">
|
<select id="selectStockTfrLargeStatements" resultMap="BankTagStatementHitResultMap">
|
||||||
@@ -824,19 +1075,119 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<select id="selectSalaryQuickTransferObjects" resultMap="BankTagObjectHitResultMap">
|
<select id="selectSalaryQuickTransferObjects" resultMap="BankTagObjectHitResultMap">
|
||||||
select
|
select
|
||||||
'STAFF_ID_CARD' AS objectType,
|
'STAFF_ID_CARD' AS objectType,
|
||||||
'' AS objectKey,
|
t.objectKey AS objectKey,
|
||||||
'占位SQL,待补充真实规则' AS reasonDetail
|
CONCAT(
|
||||||
from ccdi_bank_statement bs
|
'工资入账 ', CAST(t.salaryAmount AS CHAR),
|
||||||
where 1 = 0
|
' 元后24小时内转出 ', CAST(t.transferAmount AS CHAR),
|
||||||
|
' 元,占比 ', CAST(t.transferRatioPct AS CHAR), '%'
|
||||||
|
) AS reasonDetail
|
||||||
|
from (
|
||||||
|
select
|
||||||
|
salary.objectKey AS objectKey,
|
||||||
|
MAX(salary.salaryAmount) AS salaryAmount,
|
||||||
|
MAX(out_trade.transferAmount) AS transferAmount,
|
||||||
|
ROUND(MAX(out_trade.transferAmount / NULLIF(salary.salaryAmount, 0)) * 100, 2) AS transferRatioPct
|
||||||
|
from (
|
||||||
|
select
|
||||||
|
staff.id_card AS objectKey,
|
||||||
|
IFNULL(bs.AMOUNT_CR, 0) AS salaryAmount,
|
||||||
|
COALESCE(
|
||||||
|
STR_TO_DATE(LEFT(TRIM(bs.TRX_DATE), 19), '%Y-%m-%d %H:%i:%s'),
|
||||||
|
STR_TO_DATE(LEFT(TRIM(bs.TRX_DATE), 10), '%Y-%m-%d')
|
||||||
|
) AS salaryTime
|
||||||
|
from ccdi_bank_statement bs
|
||||||
|
inner join ccdi_base_staff staff on staff.id_card = bs.cret_no
|
||||||
|
where bs.project_id = #{projectId}
|
||||||
|
and IFNULL(bs.AMOUNT_CR, 0) > 0
|
||||||
|
and <include refid="salaryIncomePredicate"/>
|
||||||
|
) salary
|
||||||
|
inner join (
|
||||||
|
select
|
||||||
|
salary_source.objectKey AS objectKey,
|
||||||
|
salary_source.salaryTime AS salaryTime,
|
||||||
|
ROUND(SUM(IFNULL(out_bs.AMOUNT_DR, 0)), 2) AS transferAmount
|
||||||
|
from (
|
||||||
|
select
|
||||||
|
staff.id_card AS objectKey,
|
||||||
|
COALESCE(
|
||||||
|
STR_TO_DATE(LEFT(TRIM(bs.TRX_DATE), 19), '%Y-%m-%d %H:%i:%s'),
|
||||||
|
STR_TO_DATE(LEFT(TRIM(bs.TRX_DATE), 10), '%Y-%m-%d')
|
||||||
|
) AS salaryTime
|
||||||
|
from ccdi_bank_statement bs
|
||||||
|
inner join ccdi_base_staff staff on staff.id_card = bs.cret_no
|
||||||
|
where bs.project_id = #{projectId}
|
||||||
|
and IFNULL(bs.AMOUNT_CR, 0) > 0
|
||||||
|
and <include refid="salaryIncomePredicate"/>
|
||||||
|
) salary_source
|
||||||
|
inner join ccdi_bank_statement out_bs
|
||||||
|
on out_bs.project_id = #{projectId}
|
||||||
|
and out_bs.cret_no = salary_source.objectKey
|
||||||
|
and IFNULL(out_bs.AMOUNT_DR, 0) > 0
|
||||||
|
and COALESCE(
|
||||||
|
STR_TO_DATE(LEFT(TRIM(out_bs.TRX_DATE), 19), '%Y-%m-%d %H:%i:%s'),
|
||||||
|
STR_TO_DATE(LEFT(TRIM(out_bs.TRX_DATE), 10), '%Y-%m-%d')
|
||||||
|
) > salary_source.salaryTime
|
||||||
|
and COALESCE(
|
||||||
|
STR_TO_DATE(LEFT(TRIM(out_bs.TRX_DATE), 19), '%Y-%m-%d %H:%i:%s'),
|
||||||
|
STR_TO_DATE(LEFT(TRIM(out_bs.TRX_DATE), 10), '%Y-%m-%d')
|
||||||
|
) <= DATE_ADD(salary_source.salaryTime, INTERVAL 24 HOUR)
|
||||||
|
group by salary_source.objectKey, salary_source.salaryTime
|
||||||
|
) out_trade
|
||||||
|
on out_trade.objectKey = salary.objectKey
|
||||||
|
and out_trade.salaryTime = salary.salaryTime
|
||||||
|
where out_trade.transferAmount / NULLIF(salary.salaryAmount, 0) > 0.8
|
||||||
|
group by salary.objectKey
|
||||||
|
) t
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectSalaryUnusedObjects" resultMap="BankTagObjectHitResultMap">
|
<select id="selectSalaryUnusedObjects" resultMap="BankTagObjectHitResultMap">
|
||||||
select
|
select
|
||||||
'STAFF_ID_CARD' AS objectType,
|
'STAFF_ID_CARD' AS objectType,
|
||||||
'' AS objectKey,
|
t.objectKey AS objectKey,
|
||||||
'占位SQL,待补充真实规则' AS reasonDetail
|
CONCAT(
|
||||||
from ccdi_bank_statement bs
|
'工资入账 ', CAST(t.salaryAmount AS CHAR),
|
||||||
where 1 = 0
|
' 元后30天内无消费或转账支出'
|
||||||
|
) AS reasonDetail
|
||||||
|
from (
|
||||||
|
select
|
||||||
|
salary.objectKey AS objectKey,
|
||||||
|
MAX(salary.salaryAmount) AS salaryAmount
|
||||||
|
from (
|
||||||
|
select
|
||||||
|
staff.id_card AS objectKey,
|
||||||
|
IFNULL(bs.AMOUNT_CR, 0) AS salaryAmount,
|
||||||
|
COALESCE(
|
||||||
|
STR_TO_DATE(LEFT(TRIM(bs.TRX_DATE), 19), '%Y-%m-%d %H:%i:%s'),
|
||||||
|
STR_TO_DATE(LEFT(TRIM(bs.TRX_DATE), 10), '%Y-%m-%d')
|
||||||
|
) AS salaryTime
|
||||||
|
from ccdi_bank_statement bs
|
||||||
|
inner join ccdi_base_staff staff on staff.id_card = bs.cret_no
|
||||||
|
where bs.project_id = #{projectId}
|
||||||
|
and IFNULL(bs.AMOUNT_CR, 0) > 0
|
||||||
|
and <include refid="salaryIncomePredicate"/>
|
||||||
|
) salary
|
||||||
|
where not exists (
|
||||||
|
select 1
|
||||||
|
from ccdi_bank_statement expense_bs
|
||||||
|
where expense_bs.project_id = #{projectId}
|
||||||
|
and expense_bs.cret_no = salary.objectKey
|
||||||
|
and IFNULL(expense_bs.AMOUNT_DR, 0) > 0
|
||||||
|
and COALESCE(
|
||||||
|
STR_TO_DATE(LEFT(TRIM(expense_bs.TRX_DATE), 19), '%Y-%m-%d %H:%i:%s'),
|
||||||
|
STR_TO_DATE(LEFT(TRIM(expense_bs.TRX_DATE), 10), '%Y-%m-%d')
|
||||||
|
) > salary.salaryTime
|
||||||
|
and COALESCE(
|
||||||
|
STR_TO_DATE(LEFT(TRIM(expense_bs.TRX_DATE), 19), '%Y-%m-%d %H:%i:%s'),
|
||||||
|
STR_TO_DATE(LEFT(TRIM(expense_bs.TRX_DATE), 10), '%Y-%m-%d')
|
||||||
|
) <= DATE_ADD(salary.salaryTime, INTERVAL 30 DAY)
|
||||||
|
and not (
|
||||||
|
IFNULL(expense_bs.USER_MEMO, '') REGEXP '代扣|个税|社保|公积金|水费|电费|燃气|话费|党费|医保'
|
||||||
|
or IFNULL(expense_bs.CASH_TYPE, '') REGEXP '代扣|个税|社保|公积金'
|
||||||
|
or IFNULL(expense_bs.CUSTOMER_ACCOUNT_NAME, '') REGEXP '税务|社保|公积金'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
group by salary.objectKey
|
||||||
|
) t
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectLargeStockTradingStatements" resultMap="BankTagStatementHitResultMap">
|
<select id="selectLargeStockTradingStatements" resultMap="BankTagStatementHitResultMap">
|
||||||
|
|||||||
@@ -28,6 +28,15 @@ class CcdiBankTagAnalysisMapperXmlTest {
|
|||||||
"selectStockTfrLargeStatements",
|
"selectStockTfrLargeStatements",
|
||||||
"selectLargeStockTradingStatements"
|
"selectLargeStockTradingStatements"
|
||||||
);
|
);
|
||||||
|
private static final List<String> PHASE_TWO_OBJECT_SELECT_IDS = List.of(
|
||||||
|
"selectLowIncomeRelativeLargeTransactionObjects",
|
||||||
|
"selectMultiPartyGamblingTransferObjects",
|
||||||
|
"selectMonthlyFixedIncomeObjects",
|
||||||
|
"selectFixedCounterpartyTransferObjects",
|
||||||
|
"selectSupplierConcentrationObjects",
|
||||||
|
"selectSalaryQuickTransferObjects",
|
||||||
|
"selectSalaryUnusedObjects"
|
||||||
|
);
|
||||||
private static final List<String> PLACEHOLDER_SELECT_IDS = List.of(
|
private static final List<String> PLACEHOLDER_SELECT_IDS = List.of(
|
||||||
"selectAbnormalCustomerTransactionStatements",
|
"selectAbnormalCustomerTransactionStatements",
|
||||||
"selectLowIncomeRelativeLargeTransactionObjects",
|
"selectLowIncomeRelativeLargeTransactionObjects",
|
||||||
@@ -91,7 +100,7 @@ class CcdiBankTagAnalysisMapperXmlTest {
|
|||||||
void placeholderRules_shouldUseEmptyResultSqlTemplate() throws Exception {
|
void placeholderRules_shouldUseEmptyResultSqlTemplate() throws Exception {
|
||||||
String xml = readXml(RESOURCE);
|
String xml = readXml(RESOURCE);
|
||||||
assertTrue(xml.contains("占位SQL,待补充真实规则"));
|
assertTrue(xml.contains("占位SQL,待补充真实规则"));
|
||||||
assertEquals(13, countMatches(xml, "where 1 = 0"));
|
assertEquals(6, countMatches(xml, "where 1 = 0"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -117,6 +126,18 @@ class CcdiBankTagAnalysisMapperXmlTest {
|
|||||||
assertTrue(!selectSql.contains("where 1 = 0"));
|
assertTrue(!selectSql.contains("where 1 = 0"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void phaseTwoObjectRules_shouldUseRealSqlAndKeepObjectHitFields() throws Exception {
|
||||||
|
String xml = readXml(RESOURCE);
|
||||||
|
for (String selectId : PHASE_TWO_OBJECT_SELECT_IDS) {
|
||||||
|
String selectSql = extractSelectSql(xml, selectId);
|
||||||
|
assertTrue(selectSql.contains("'STAFF_ID_CARD' AS objectType"), () -> selectId + " 缺少 objectType");
|
||||||
|
assertTrue(selectSql.contains("AS objectKey"), () -> selectId + " 缺少 objectKey");
|
||||||
|
assertTrue(selectSql.contains("reasonDetail"), () -> selectId + " 缺少 reasonDetail");
|
||||||
|
assertTrue(!selectSql.contains("where 1 = 0"), () -> selectId + " 仍是占位 SQL");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void assetRegistrationMismatchRules_shouldUseRealSqlAndAssetTable() throws Exception {
|
void assetRegistrationMismatchRules_shouldUseRealSqlAndAssetTable() throws Exception {
|
||||||
String xml = readXml(RESOURCE);
|
String xml = readXml(RESOURCE);
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import org.springframework.test.util.ReflectionTestUtils;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
@@ -327,6 +328,84 @@ class CcdiBankTagServiceImplTest {
|
|||||||
verify(projectService).updateProjectStatus(40L, "0", "tester");
|
verify(projectService).updateProjectStatus(40L, "0", "tester");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void rebuildProject_shouldDispatchPhaseTwoThresholdObjectRulesWithResolvedThresholds() {
|
||||||
|
ReflectionTestUtils.setField(service, "tagRuleExecutor", (Executor) Runnable::run);
|
||||||
|
|
||||||
|
CcdiBankTagRule gamblingRule = buildRule("SUSPICIOUS_GAMBLING", "疑似赌博",
|
||||||
|
"MULTI_PARTY_GAMBLING_TRANSFER", "疑似赌博交易", "OBJECT");
|
||||||
|
CcdiBankTagRule monthlyRule = buildRule("SUSPICIOUS_PART_TIME", "可疑兼职",
|
||||||
|
"MONTHLY_FIXED_INCOME", "疑似兼职", "OBJECT");
|
||||||
|
CcdiBankTagRule fixedCounterpartyRule = buildRule("SUSPICIOUS_PART_TIME", "可疑兼职",
|
||||||
|
"FIXED_COUNTERPARTY_TRANSFER", "疑似兼职", "OBJECT");
|
||||||
|
|
||||||
|
BankTagRuleExecutionConfig gamblingConfig = buildConfig(40L, gamblingRule);
|
||||||
|
gamblingConfig.setThresholdValues(Map.of("MULTI_PARTY_AMT_MIN", "500", "MULTI_PARTY_AMT_MAX", "5000"));
|
||||||
|
BankTagRuleExecutionConfig monthlyConfig = buildConfig(40L, monthlyRule);
|
||||||
|
monthlyConfig.setThresholdValues(Map.of("MONTHLY_FIXED_INCOME", "5000"));
|
||||||
|
BankTagRuleExecutionConfig fixedCounterpartyConfig = buildConfig(40L, fixedCounterpartyRule);
|
||||||
|
fixedCounterpartyConfig.setThresholdValues(Map.of(
|
||||||
|
"FIXED_COUNTERPARTY_TRANSFER_MIN", "3000",
|
||||||
|
"FIXED_COUNTERPARTY_TRANSFER_MAX", "15000"
|
||||||
|
));
|
||||||
|
|
||||||
|
when(ruleMapper.selectEnabledRules("SUSPICIOUS_GAMBLING")).thenReturn(List.of(gamblingRule));
|
||||||
|
when(configResolver.resolve(40L, gamblingRule)).thenReturn(gamblingConfig);
|
||||||
|
when(analysisMapper.selectMultiPartyGamblingTransferObjects(40L, new BigDecimal("500"), new BigDecimal("5000")))
|
||||||
|
.thenReturn(List.of());
|
||||||
|
|
||||||
|
when(ruleMapper.selectEnabledRules("SUSPICIOUS_PART_TIME")).thenReturn(List.of(monthlyRule, fixedCounterpartyRule));
|
||||||
|
when(configResolver.resolve(40L, monthlyRule)).thenReturn(monthlyConfig);
|
||||||
|
when(configResolver.resolve(40L, fixedCounterpartyRule)).thenReturn(fixedCounterpartyConfig);
|
||||||
|
when(analysisMapper.selectMonthlyFixedIncomeObjects(40L, new BigDecimal("5000"))).thenReturn(List.of());
|
||||||
|
when(analysisMapper.selectFixedCounterpartyTransferObjects(40L, new BigDecimal("3000"), new BigDecimal("15000")))
|
||||||
|
.thenReturn(List.of());
|
||||||
|
|
||||||
|
service.rebuildProject(40L, "SUSPICIOUS_GAMBLING", "admin", TriggerType.MANUAL);
|
||||||
|
service.rebuildProject(40L, "SUSPICIOUS_PART_TIME", "admin", TriggerType.MANUAL);
|
||||||
|
|
||||||
|
verify(analysisMapper).selectMultiPartyGamblingTransferObjects(40L, new BigDecimal("500"), new BigDecimal("5000"));
|
||||||
|
verify(analysisMapper).selectMonthlyFixedIncomeObjects(40L, new BigDecimal("5000"));
|
||||||
|
verify(analysisMapper).selectFixedCounterpartyTransferObjects(40L, new BigDecimal("3000"), new BigDecimal("15000"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void rebuildProject_shouldDispatchPhaseTwoObjectRulesWithoutExtraThresholds() {
|
||||||
|
ReflectionTestUtils.setField(service, "tagRuleExecutor", (Executor) Runnable::run);
|
||||||
|
|
||||||
|
CcdiBankTagRule lowIncomeRule = buildRule("ABNORMAL_TRANSACTION", "异常交易",
|
||||||
|
"LOW_INCOME_RELATIVE_LARGE_TRANSACTION", "低收入亲属大额交易", "OBJECT");
|
||||||
|
CcdiBankTagRule supplierRule = buildRule("SUSPICIOUS_PURCHASE", "可疑采购",
|
||||||
|
"SUPPLIER_CONCENTRATION", "可疑采购", "OBJECT");
|
||||||
|
CcdiBankTagRule salaryQuickRule = buildRule("ABNORMAL_BEHAVIOR", "异常行为",
|
||||||
|
"SALARY_QUICK_TRANSFER", "工资快速转出", "OBJECT");
|
||||||
|
CcdiBankTagRule salaryUnusedRule = buildRule("ABNORMAL_BEHAVIOR", "异常行为",
|
||||||
|
"SALARY_UNUSED", "工资无使用记录", "OBJECT");
|
||||||
|
|
||||||
|
when(ruleMapper.selectEnabledRules("ABNORMAL_TRANSACTION")).thenReturn(List.of(lowIncomeRule));
|
||||||
|
when(configResolver.resolve(40L, lowIncomeRule)).thenReturn(buildConfig(40L, lowIncomeRule));
|
||||||
|
when(analysisMapper.selectLowIncomeRelativeLargeTransactionObjects(40L)).thenReturn(List.of());
|
||||||
|
|
||||||
|
when(ruleMapper.selectEnabledRules("SUSPICIOUS_PURCHASE")).thenReturn(List.of(supplierRule));
|
||||||
|
when(configResolver.resolve(40L, supplierRule)).thenReturn(buildConfig(40L, supplierRule));
|
||||||
|
when(analysisMapper.selectSupplierConcentrationObjects(40L)).thenReturn(List.of());
|
||||||
|
|
||||||
|
when(ruleMapper.selectEnabledRules("ABNORMAL_BEHAVIOR")).thenReturn(List.of(salaryQuickRule, salaryUnusedRule));
|
||||||
|
when(configResolver.resolve(40L, salaryQuickRule)).thenReturn(buildConfig(40L, salaryQuickRule));
|
||||||
|
when(configResolver.resolve(40L, salaryUnusedRule)).thenReturn(buildConfig(40L, salaryUnusedRule));
|
||||||
|
when(analysisMapper.selectSalaryQuickTransferObjects(40L)).thenReturn(List.of());
|
||||||
|
when(analysisMapper.selectSalaryUnusedObjects(40L)).thenReturn(List.of());
|
||||||
|
|
||||||
|
service.rebuildProject(40L, "ABNORMAL_TRANSACTION", "admin", TriggerType.MANUAL);
|
||||||
|
service.rebuildProject(40L, "SUSPICIOUS_PURCHASE", "admin", TriggerType.MANUAL);
|
||||||
|
service.rebuildProject(40L, "ABNORMAL_BEHAVIOR", "admin", TriggerType.MANUAL);
|
||||||
|
|
||||||
|
verify(analysisMapper).selectLowIncomeRelativeLargeTransactionObjects(40L);
|
||||||
|
verify(analysisMapper).selectSupplierConcentrationObjects(40L);
|
||||||
|
verify(analysisMapper).selectSalaryQuickTransferObjects(40L);
|
||||||
|
verify(analysisMapper).selectSalaryUnusedObjects(40L);
|
||||||
|
}
|
||||||
|
|
||||||
private CcdiBankTagRule buildRule(String modelCode, String modelName, String ruleCode, String ruleName, String resultType) {
|
private CcdiBankTagRule buildRule(String modelCode, String modelName, String ruleCode, String ruleName, String resultType) {
|
||||||
CcdiBankTagRule rule = new CcdiBankTagRule();
|
CcdiBankTagRule rule = new CcdiBankTagRule();
|
||||||
rule.setModelCode(modelCode);
|
rule.setModelCode(modelCode);
|
||||||
|
|||||||
Reference in New Issue
Block a user