oss file updated, profitl loss as per the day month and also with date select
Fineract Build & Cucumber tests (without E2E tests) / verify (main, cucumber) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (progressive-loan, build-progressive-loan) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 3 of 10) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (main, build-core) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 1 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 10 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 2 of 10) (push) Canceled after 0s
Fineract Docker Builds / build (false, docker-compose-postgresql.yml, postgresql) (push) Canceled after 0s
Fineract Docker Builds / build (true, docker-compose.yml, mariadb) (push) Canceled after 0s
Fineract Documentation build / build (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-5) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-3) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 4 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 5 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 6 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 7 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 8 of 10) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-2) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 9 of 10) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-5) (push) Canceled after 0s
Fineract Liquibase Only mode - PostgreSQL / test (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with ActiveMQ (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-5) (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with Kafka (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (main, cucumber) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (progressive-loan, build-progressive-loan) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 3 of 10) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (main, build-core) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 1 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 10 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 2 of 10) (push) Canceled after 0s
Fineract Docker Builds / build (false, docker-compose-postgresql.yml, postgresql) (push) Canceled after 0s
Fineract Docker Builds / build (true, docker-compose.yml, mariadb) (push) Canceled after 0s
Fineract Documentation build / build (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-5) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-3) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 4 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 5 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 6 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 7 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 8 of 10) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-2) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 9 of 10) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-5) (push) Canceled after 0s
Fineract Liquibase Only mode - PostgreSQL / test (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with ActiveMQ (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-5) (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with Kafka (push) Canceled after 0s
This commit is contained in:
+16
@@ -52,6 +52,14 @@ public class AmlTransactionRule {
|
||||
@Column(name = "threshold_amount", precision = 19, scale = 6)
|
||||
private BigDecimal thresholdAmount;
|
||||
|
||||
/** Risk-category-tiered overrides of {@link #thresholdAmount}. Null on both means the rule is
|
||||
* not tiered; {@link #thresholdAmount} is used for every client regardless of risk category. */
|
||||
@Column(name = "threshold_amount_medium_risk", precision = 19, scale = 6)
|
||||
private BigDecimal thresholdAmountMediumRisk;
|
||||
|
||||
@Column(name = "threshold_amount_high_risk", precision = 19, scale = 6)
|
||||
private BigDecimal thresholdAmountHighRisk;
|
||||
|
||||
@Column(name = "rule_type", nullable = false, length = 20)
|
||||
private String ruleType;
|
||||
|
||||
@@ -86,6 +94,14 @@ public class AmlTransactionRule {
|
||||
return thresholdAmount;
|
||||
}
|
||||
|
||||
public BigDecimal getThresholdAmountMediumRisk() {
|
||||
return thresholdAmountMediumRisk;
|
||||
}
|
||||
|
||||
public BigDecimal getThresholdAmountHighRisk() {
|
||||
return thresholdAmountHighRisk;
|
||||
}
|
||||
|
||||
public AmlRuleType getRuleType() {
|
||||
return AmlRuleType.valueOf(ruleType);
|
||||
}
|
||||
|
||||
+32
-3
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.aml.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -27,6 +28,8 @@ import org.apache.fineract.portfolio.aml.domain.AmlAlertRepository;
|
||||
import org.apache.fineract.portfolio.aml.domain.AmlAppliesTo;
|
||||
import org.apache.fineract.portfolio.aml.domain.AmlTransactionRule;
|
||||
import org.apache.fineract.portfolio.aml.domain.AmlTransactionRuleRepository;
|
||||
import org.apache.fineract.portfolio.client.domain.ClientKyc;
|
||||
import org.apache.fineract.portfolio.client.domain.ClientKycRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -35,8 +38,12 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
@Transactional
|
||||
public class AmlRuleEvaluationServiceImpl implements AmlRuleEvaluationService {
|
||||
|
||||
private static final int MEDIUM_RISK = 2;
|
||||
private static final int HIGH_RISK = 3;
|
||||
|
||||
private final AmlTransactionRuleRepository ruleRepository;
|
||||
private final AmlAlertRepository alertRepository;
|
||||
private final ClientKycRepository clientKycRepository;
|
||||
|
||||
@Override
|
||||
public List<AmlAlert> evaluate(AmlTransactionContext context) {
|
||||
@@ -56,20 +63,42 @@ public class AmlRuleEvaluationServiceImpl implements AmlRuleEvaluationService {
|
||||
}
|
||||
|
||||
private boolean isHit(AmlTransactionRule rule, AmlTransactionContext context) {
|
||||
if (rule.getThresholdAmount() == null) {
|
||||
final BigDecimal threshold = resolveThreshold(rule, context);
|
||||
if (threshold == null) {
|
||||
// Pattern-only VELOCITY rules (e.g. same-day movement) need bespoke detection logic
|
||||
// per rule and are not yet evaluated here - they exist in the catalog for future work.
|
||||
return false;
|
||||
}
|
||||
switch (rule.getRuleType()) {
|
||||
case THRESHOLD:
|
||||
return context.getAmount().compareTo(rule.getThresholdAmount()) >= 0;
|
||||
return context.getAmount().compareTo(threshold) >= 0;
|
||||
case STRUCTURING:
|
||||
case VELOCITY:
|
||||
return context.getWindowAggregateAmount() != null
|
||||
&& context.getWindowAggregateAmount().compareTo(rule.getThresholdAmount()) >= 0;
|
||||
&& context.getWindowAggregateAmount().compareTo(threshold) >= 0;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rules with both tiered columns null use {@code thresholdAmount} for every client, unchanged
|
||||
* from prior behaviour. Tiered rules look up the transacting client's current KYC risk category
|
||||
* and pick the matching tier, falling back to {@code thresholdAmount} for Low-risk/unclassified
|
||||
* clients.
|
||||
*/
|
||||
private BigDecimal resolveThreshold(AmlTransactionRule rule, AmlTransactionContext context) {
|
||||
if (rule.getThresholdAmountMediumRisk() == null && rule.getThresholdAmountHighRisk() == null) {
|
||||
return rule.getThresholdAmount();
|
||||
}
|
||||
final Integer riskCategory = clientKycRepository.findByClientId(context.getClient().getId()).map(ClientKyc::getRiskCategoryValue)
|
||||
.orElse(null);
|
||||
if (riskCategory != null && riskCategory == HIGH_RISK && rule.getThresholdAmountHighRisk() != null) {
|
||||
return rule.getThresholdAmountHighRisk();
|
||||
}
|
||||
if (riskCategory != null && riskCategory == MEDIUM_RISK && rule.getThresholdAmountMediumRisk() != null) {
|
||||
return rule.getThresholdAmountMediumRisk();
|
||||
}
|
||||
return rule.getThresholdAmount();
|
||||
}
|
||||
}
|
||||
|
||||
+38
-1
@@ -46,6 +46,16 @@ public final class KycRiskRuleData implements Serializable {
|
||||
private final String willfulDefaulter;
|
||||
private final String ecgcSalFlag;
|
||||
private final String dormantFlag;
|
||||
/** Populated only for rules that also have a live-transaction-monitoring counterpart in
|
||||
* {@code m_aml_transaction_rule} (linked via source_client_risk_rule_id) - distinct from the
|
||||
* client-onboarding income/turnover fields above, which drive KYC-time risk categorization. */
|
||||
private final BigDecimal txnThresholdAmount;
|
||||
private final String txnRuleType;
|
||||
private final Integer txnWindowDays;
|
||||
/** Risk-category-tiered overrides of {@link #txnThresholdAmount}, populated only when the
|
||||
* linked {@code m_aml_transaction_rule} row has tiering configured (e.g. RTGS monitoring). */
|
||||
private final BigDecimal txnThresholdAmountMediumRisk;
|
||||
private final BigDecimal txnThresholdAmountHighRisk;
|
||||
|
||||
public KycRiskRuleData(final Long id, final String ruleName, final Integer legalFormId,
|
||||
final Long occupationCategoryCvId, final String occupationCategoryName,
|
||||
@@ -55,7 +65,9 @@ public final class KycRiskRuleData implements Serializable {
|
||||
final BigDecimal minAnnualTurnover, final BigDecimal maxAnnualTurnover,
|
||||
final Integer riskCategory, final String reason, final Integer orderPosition,
|
||||
final String amlCheckStatus, final String bannedEntityMatch,
|
||||
final String willfulDefaulter, final String ecgcSalFlag, final String dormantFlag) {
|
||||
final String willfulDefaulter, final String ecgcSalFlag, final String dormantFlag,
|
||||
final BigDecimal txnThresholdAmount, final String txnRuleType, final Integer txnWindowDays,
|
||||
final BigDecimal txnThresholdAmountMediumRisk, final BigDecimal txnThresholdAmountHighRisk) {
|
||||
this.id = id;
|
||||
this.ruleName = ruleName;
|
||||
this.legalFormId = legalFormId;
|
||||
@@ -77,6 +89,11 @@ public final class KycRiskRuleData implements Serializable {
|
||||
this.willfulDefaulter = willfulDefaulter;
|
||||
this.ecgcSalFlag = ecgcSalFlag;
|
||||
this.dormantFlag = dormantFlag;
|
||||
this.txnThresholdAmount = txnThresholdAmount;
|
||||
this.txnRuleType = txnRuleType;
|
||||
this.txnWindowDays = txnWindowDays;
|
||||
this.txnThresholdAmountMediumRisk = txnThresholdAmountMediumRisk;
|
||||
this.txnThresholdAmountHighRisk = txnThresholdAmountHighRisk;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
@@ -162,4 +179,24 @@ public final class KycRiskRuleData implements Serializable {
|
||||
public String getDormantFlag() {
|
||||
return dormantFlag;
|
||||
}
|
||||
|
||||
public BigDecimal getTxnThresholdAmount() {
|
||||
return txnThresholdAmount;
|
||||
}
|
||||
|
||||
public String getTxnRuleType() {
|
||||
return txnRuleType;
|
||||
}
|
||||
|
||||
public Integer getTxnWindowDays() {
|
||||
return txnWindowDays;
|
||||
}
|
||||
|
||||
public BigDecimal getTxnThresholdAmountMediumRisk() {
|
||||
return txnThresholdAmountMediumRisk;
|
||||
}
|
||||
|
||||
public BigDecimal getTxnThresholdAmountHighRisk() {
|
||||
return txnThresholdAmountHighRisk;
|
||||
}
|
||||
}
|
||||
|
||||
+16
-3
@@ -19,8 +19,12 @@
|
||||
package org.apache.fineract.portfolio.client.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.portfolio.aml.domain.AmlTransactionRule;
|
||||
import org.apache.fineract.portfolio.aml.domain.AmlTransactionRuleRepository;
|
||||
import org.apache.fineract.portfolio.client.data.KycRiskRuleData;
|
||||
import org.apache.fineract.portfolio.client.domain.ClientRiskRule;
|
||||
import org.apache.fineract.portfolio.client.domain.ClientRiskRuleRepository;
|
||||
@@ -33,14 +37,18 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
public class KycRiskRulesReadPlatformServiceImpl implements KycRiskRulesReadPlatformService {
|
||||
|
||||
private final ClientRiskRuleRepository repository;
|
||||
private final AmlTransactionRuleRepository amlTransactionRuleRepository;
|
||||
|
||||
@Override
|
||||
public List<KycRiskRuleData> retrieveAllRules() {
|
||||
final List<ClientRiskRule> rules = this.repository.findAllOrderedByOrderPosition();
|
||||
return rules.stream().map(this::mapToData).collect(Collectors.toList());
|
||||
final Map<Long, AmlTransactionRule> txnRulesBySourceId = this.amlTransactionRuleRepository.findAll().stream()
|
||||
.filter(txn -> txn.getSourceClientRiskRuleId() != null)
|
||||
.collect(Collectors.toMap(AmlTransactionRule::getSourceClientRiskRuleId, Function.identity(), (a, b) -> a));
|
||||
return rules.stream().map(rule -> mapToData(rule, txnRulesBySourceId.get(rule.getId()))).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private KycRiskRuleData mapToData(final ClientRiskRule rule) {
|
||||
private KycRiskRuleData mapToData(final ClientRiskRule rule, final AmlTransactionRule txnRule) {
|
||||
final Long occCatId = rule.getOccupationCategory() != null ? rule.getOccupationCategory().getId() : null;
|
||||
final String occCatName = rule.getOccupationCategory() != null ? rule.getOccupationCategory().getLabel() : null;
|
||||
final Long occId = rule.getOccupation() != null ? rule.getOccupation().getId() : null;
|
||||
@@ -67,7 +75,12 @@ public class KycRiskRulesReadPlatformServiceImpl implements KycRiskRulesReadPlat
|
||||
rule.getBannedEntityMatch(),
|
||||
rule.getWillfulDefaulter(),
|
||||
rule.getEcgcSalFlag(),
|
||||
rule.getDormantFlag()
|
||||
rule.getDormantFlag(),
|
||||
txnRule != null ? txnRule.getThresholdAmount() : null,
|
||||
txnRule != null ? txnRule.getRuleType().name() : null,
|
||||
txnRule != null ? txnRule.getWindowDays() : null,
|
||||
txnRule != null ? txnRule.getThresholdAmountMediumRisk() : null,
|
||||
txnRule != null ? txnRule.getThresholdAmountHighRisk() : null
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -490,4 +490,7 @@
|
||||
<include file="parts/0435_add_aml_officer_and_principal_officer_roles.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0436_fix_missing_client_risk_rule_columns.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0437_update_aml_columns_for_risk_rules.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0438_add_tiered_thresholds_and_low_balance_rule.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0439_fill_client_risk_rule_income_turnover_nulls.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0440_seed_aml_test_alerts.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.13.xsd">
|
||||
|
||||
<!-- Optional risk-category-tiered thresholds. Null on both columns means the rule is not
|
||||
tiered and threshold_amount alone is used (unchanged behaviour for every pre-existing rule). -->
|
||||
<changeSet author="fineract" id="0438-1">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not><columnExists tableName="m_aml_transaction_rule" columnName="threshold_amount_medium_risk"/></not>
|
||||
</preConditions>
|
||||
<addColumn tableName="m_aml_transaction_rule">
|
||||
<column name="threshold_amount_medium_risk" type="DECIMAL(19,6)">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="fineract" id="0438-2">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not><columnExists tableName="m_aml_transaction_rule" columnName="threshold_amount_high_risk"/></not>
|
||||
</preConditions>
|
||||
<addColumn tableName="m_aml_transaction_rule">
|
||||
<column name="threshold_amount_high_risk" type="DECIMAL(19,6)">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
<!-- RTGS monitoring: Medium-risk clients are flagged at INR 5,00,000, High-risk at INR 20,00,000.
|
||||
threshold_amount (2,000,000) remains the fallback for Low-risk/unclassified clients. -->
|
||||
<changeSet author="fineract" id="0438-3">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_aml_transaction_rule WHERE rule_code = 'RTGS_HIGH_VALUE' AND threshold_amount_medium_risk IS NOT NULL</sqlCheck>
|
||||
</preConditions>
|
||||
<sql>
|
||||
UPDATE m_aml_transaction_rule
|
||||
SET threshold_amount_medium_risk = 500000,
|
||||
threshold_amount_high_risk = 2000000
|
||||
WHERE rule_code = 'RTGS_HIGH_VALUE';
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
<!-- Rule 1 from the legacy Rules Parameter catalog: "Maintaining a low or overdrawn balance
|
||||
with high activity" (order_position 1). The legacy screen reports a single INR 10,00,000
|
||||
figure across three distinct parameters (average balance period, minimum balance, max
|
||||
transaction count), which does not correspond to any threshold/window shape this catalog
|
||||
currently evaluates (THRESHOLD/STRUCTURING/VELOCITY all key off a transaction AMOUNT, not
|
||||
an account balance level). Seeded here for catalog/display parity with m_client_risk_rule,
|
||||
with is_active = false so it is never picked up by AmlRuleEvaluationServiceImpl until a
|
||||
balance-based rule type is built. -->
|
||||
<changeSet author="fineract" id="0438-4">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_aml_transaction_rule WHERE rule_code = 'LOW_BALANCE_HIGH_ACTIVITY'</sqlCheck>
|
||||
</preConditions>
|
||||
<sql>
|
||||
INSERT INTO m_aml_transaction_rule
|
||||
(rule_code, description, applies_to, threshold_amount, rule_type, window_days, source_client_risk_rule_id, is_active)
|
||||
VALUES
|
||||
('LOW_BALANCE_HIGH_ACTIVITY', 'Maintaining a low or overdrawn balance with high activity', 'SAVINGS', 1000000, 'THRESHOLD', null,
|
||||
(SELECT id FROM m_client_risk_rule WHERE order_position = 1 AND aml_check_status IS NOT NULL), false);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.13.xsd">
|
||||
|
||||
<changeSet author="fineract" id="0439-1">
|
||||
<validCheckSum>*</validCheckSum>
|
||||
<sql>
|
||||
-- 1. High Risk Occupations (Real Estate, Importer/Exporter, Commission Agent, Financial Advisor)
|
||||
UPDATE m_client_risk_rule
|
||||
SET min_monthly_income = 200000.0,
|
||||
min_annual_income = 2400000.0
|
||||
WHERE order_position IN (20, 30, 40, 50);
|
||||
|
||||
-- 2. Medium Risk Occupations
|
||||
UPDATE m_client_risk_rule
|
||||
SET min_monthly_income = 50000.0,
|
||||
max_monthly_income = 200000.0,
|
||||
min_annual_income = 600000.0,
|
||||
max_annual_income = 2400000.0
|
||||
WHERE order_position BETWEEN 90 AND 240;
|
||||
|
||||
-- 3. Low Risk Occupations
|
||||
UPDATE m_client_risk_rule
|
||||
SET min_monthly_income = 0.0,
|
||||
max_monthly_income = 50000.0,
|
||||
min_annual_income = 0.0,
|
||||
max_annual_income = 600000.0
|
||||
WHERE order_position BETWEEN 280 AND 450;
|
||||
|
||||
-- 4. Set all remaining NULL values to 0.00
|
||||
UPDATE m_client_risk_rule SET min_monthly_income = 0.0 WHERE min_monthly_income IS NULL;
|
||||
UPDATE m_client_risk_rule SET max_monthly_income = 0.0 WHERE max_monthly_income IS NULL;
|
||||
UPDATE m_client_risk_rule SET min_annual_income = 0.0 WHERE min_annual_income IS NULL;
|
||||
UPDATE m_client_risk_rule SET max_annual_income = 0.0 WHERE max_annual_income IS NULL;
|
||||
UPDATE m_client_risk_rule SET min_annual_turnover = 0.0 WHERE min_annual_turnover IS NULL;
|
||||
UPDATE m_client_risk_rule SET max_annual_turnover = 0.0 WHERE max_annual_turnover IS NULL;
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.13.xsd">
|
||||
|
||||
<changeSet author="fineract" id="0440-1">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_client WHERE external_id = 'CLIENT_RAJESH'</sqlCheck>
|
||||
</preConditions>
|
||||
<sql>
|
||||
INSERT INTO m_client (
|
||||
account_no, external_id, status_enum, office_id, display_name,
|
||||
fullname, is_staff, activation_date, office_joining_date,
|
||||
submittedon_date, legal_form_enum,
|
||||
created_on_utc, created_by,
|
||||
last_modified_on_utc, last_modified_by,
|
||||
cif_number
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
'ACC0000002', 'CLIENT_RAJESH', 300, 1, 'Rajesh Kumar',
|
||||
'Rajesh Kumar', false, CURRENT_DATE, CURRENT_DATE,
|
||||
CURRENT_DATE, 1,
|
||||
NOW(), 1,
|
||||
NOW(), 1,
|
||||
'CIF_RAJESH'
|
||||
),
|
||||
(
|
||||
'ACC0000003', 'CLIENT_SONIA', 300, 1, 'Sonia Sharma',
|
||||
'Sonia Sharma', false, CURRENT_DATE, CURRENT_DATE,
|
||||
CURRENT_DATE, 1,
|
||||
NOW(), 1,
|
||||
NOW(), 1,
|
||||
'CIF_SONIA'
|
||||
),
|
||||
(
|
||||
'ACC0000004', 'CLIENT_VIKRAM', 300, 1, 'Vikram Malhotra',
|
||||
'Vikram Malhotra', false, CURRENT_DATE, CURRENT_DATE,
|
||||
CURRENT_DATE, 1,
|
||||
NOW(), 1,
|
||||
NOW(), 1,
|
||||
'CIF_VIKRAM'
|
||||
);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="fineract" id="0440-2">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">
|
||||
SELECT COUNT(*) FROM m_aml_alert a
|
||||
JOIN m_client c ON a.client_id = c.id
|
||||
WHERE c.external_id IN ('CLIENT_RAJESH', 'CLIENT_SONIA', 'CLIENT_VIKRAM')
|
||||
</sqlCheck>
|
||||
</preConditions>
|
||||
<sql>
|
||||
INSERT INTO m_aml_alert (
|
||||
transaction_type, transaction_id, client_id, rule_id, amount, currency_code,
|
||||
raised_on, status, created_by, created_on_utc, last_modified_by, last_modified_on_utc, version
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
'SAVINGS', 1001,
|
||||
(SELECT id FROM m_client WHERE external_id = 'CLIENT_RAJESH'),
|
||||
(SELECT id FROM m_aml_transaction_rule WHERE rule_code = 'LARGE_CASH_TXN_25L'),
|
||||
3500000.000000, 'INR',
|
||||
NOW(), 'RAISED',
|
||||
1, NOW(), 1, NOW(), 0
|
||||
),
|
||||
(
|
||||
'SAVINGS', 1002,
|
||||
(SELECT id FROM m_client WHERE external_id = 'CLIENT_SONIA'),
|
||||
(SELECT id FROM m_aml_transaction_rule WHERE rule_code = 'STRUCTURING_BELOW_10L'),
|
||||
995000.000000, 'INR',
|
||||
NOW(), 'RAISED',
|
||||
1, NOW(), 1, NOW(), 0
|
||||
),
|
||||
(
|
||||
'SAVINGS', 1003,
|
||||
(SELECT id FROM m_client WHERE external_id = 'CLIENT_VIKRAM'),
|
||||
(SELECT id FROM m_aml_transaction_rule WHERE rule_code = 'PEP_ACCOUNT_MONITORING'),
|
||||
75000.000000, 'INR',
|
||||
NOW(), 'RAISED',
|
||||
1, NOW(), 1, NOW(), 0
|
||||
);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
Reference in New Issue
Block a user