feat: implement DIP/MNRL lookups and enhance Sanctions screening workflows
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 Build & Cucumber tests (without E2E tests) / verify (main, build-core) (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 Docker Builds / build (false, docker-compose-postgresql.yml, postgresql) (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 Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-5) (push) Canceled after 0s
Fineract Docker Builds / build (true, docker-compose.yml, mariadb) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 1 of 10) (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-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-5) (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 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 Documentation build / build (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 E2E Tests / E2E Tests (Shard 3 of 10) (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 E2E Tests / E2E Tests (Shard 9 of 10) (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 Messaging Smoke Tests / Smoke Test with Kafka (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 Build & Cucumber tests (without E2E tests) / verify (main, build-core) (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 Docker Builds / build (false, docker-compose-postgresql.yml, postgresql) (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 Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-5) (push) Canceled after 0s
Fineract Docker Builds / build (true, docker-compose.yml, mariadb) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 1 of 10) (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-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-5) (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 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 Documentation build / build (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 E2E Tests / E2E Tests (Shard 3 of 10) (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 E2E Tests / E2E Tests (Shard 9 of 10) (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 Messaging Smoke Tests / Smoke Test with Kafka (push) Canceled after 0s
- Implement DIP/MNRL lookup logs table, filtering, and detail review under reports. - Integrate DIP verification gating on client creation, allowing officers to record PROCEEDED/REJECTED decisions with reasons. - Upgrade Sanctions verification dialog to support comparing Name, DOB, and Nationality particulars. - Add Sanctions disposition recording (FALSE_POSITIVE / CONFIRMED_MATCH) awaiting Principal Officer approval. - Add sanctions-alert-review-dialog for reviewers to assess and escalate/clear flagged names. - Enforce strict screening reset logic on client name changes, preventing bypass of existing blocks. - Update routes and shell menu navigation to include DIP/MNRL Lookups and Sanctions Logs.
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* LOCAL TEST DIP/MNRL LOOKUP SERVICE — NOT A REAL DoT ENDPOINT.
|
||||
*
|
||||
* This stands in for the Department of Telecommunications Digital Intelligence Platform so the
|
||||
* client-onboarding flow can be exercised end to end without a live DoT connection. It invents
|
||||
* its answers. NOTHING HERE IS A REAL DIP OR MNRL CHECK.
|
||||
*
|
||||
* Mirrors scripts/mock-sms-gateway.js in intent: an unconfigured external provider gets a local
|
||||
* stand-in rather than a dangling URL, and every response is stamped so it can never be mistaken
|
||||
* for a genuine DoT result in the audit trail.
|
||||
*
|
||||
* Usage:
|
||||
* node scripts/mock-dip-lookup-service.js # listens on 8090
|
||||
* MOCK_DIP_PORT=9100 node scripts/mock-dip-lookup-service.js
|
||||
*
|
||||
* Point the backend at it:
|
||||
* FINERACT_MOBILE_LOOKUP_BASE_URL=http://127.0.0.1:8090
|
||||
*
|
||||
* BEFORE PRODUCTION: point FINERACT_MOBILE_LOOKUP_BASE_URL at the real DIP/MNRL provider and do
|
||||
* not run this. See the banner in application.properties.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const http = require('http');
|
||||
const { URL } = require('url');
|
||||
|
||||
const PORT = Number(process.env.MOCK_DIP_PORT || 8090);
|
||||
|
||||
/** Stamped into every response so a mock lookup is identifiable in the stored raw JSON. */
|
||||
const PROVIDER = 'MOCK_DIP_LOOKUP_TEST_ONLY';
|
||||
|
||||
/*
|
||||
* Fixed verdicts for numbers used in demos and manual testing. Anything not listed here comes
|
||||
* back CLEAN — the common case, so an ordinary test number does not trip the flagged-number gate.
|
||||
*
|
||||
* These overlap deliberately with DEMO_SUSPECTED_NUMBERS in MobileLookupServiceImpl: those are
|
||||
* short-circuited before the HTTP call ever happens, so they are here only to keep the two lists
|
||||
* telling the same story if that short-circuit is ever removed.
|
||||
*/
|
||||
const SUSPECTED = new Set([
|
||||
'9827123456', '9827456789', '9826234567',
|
||||
'9826987654', '9893123456', '9893765432'
|
||||
]);
|
||||
|
||||
const DISCONNECTED = new Set([
|
||||
'9000000001', '9000000002'
|
||||
]);
|
||||
|
||||
const SUSPECTED_AND_DISCONNECTED = new Set([
|
||||
'9000000003'
|
||||
]);
|
||||
|
||||
/** Strips a leading country code so 919827123456 and 9827123456 resolve alike. */
|
||||
function normalise(raw) {
|
||||
const digits = String(raw || '').replace(/\D/g, '');
|
||||
if (digits.length > 10 && digits.startsWith('91')) {
|
||||
return digits.slice(2);
|
||||
}
|
||||
return digits;
|
||||
}
|
||||
|
||||
function suspectedDetail() {
|
||||
return {
|
||||
dipStatus: 'active',
|
||||
reason: 'Reported in cyber-fraud complaints (mock data)',
|
||||
reportedBy: PROVIDER
|
||||
};
|
||||
}
|
||||
|
||||
function disconnectedDetail() {
|
||||
return {
|
||||
disconnectionReason: 'Number revoked and listed on MNRL (mock data)',
|
||||
operator: 'MOCK TELECOM'
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* The backend parser reads suspectedDetail/disconnectedDetail unconditionally and only guards
|
||||
* with isJsonNull(), so both keys must always be present — an absent key would NPE there rather
|
||||
* than surface as a clean parse failure.
|
||||
*/
|
||||
function verdictFor(mobileNumber) {
|
||||
const n = normalise(mobileNumber);
|
||||
|
||||
if (SUSPECTED_AND_DISCONNECTED.has(n)) {
|
||||
return {
|
||||
status: 'SUSPECTED_AND_DISCONNECTED',
|
||||
suspected: true,
|
||||
disconnected: true,
|
||||
suspectedDetail: suspectedDetail(),
|
||||
disconnectedDetail: disconnectedDetail(),
|
||||
message: 'Number is SUSPECTED and DISCONNECTED — found in both DIP and MNRL records'
|
||||
};
|
||||
}
|
||||
if (SUSPECTED.has(n)) {
|
||||
return {
|
||||
status: 'SUSPECTED',
|
||||
suspected: true,
|
||||
disconnected: false,
|
||||
suspectedDetail: suspectedDetail(),
|
||||
disconnectedDetail: null,
|
||||
message: 'Number is SUSPECTED — found in DIP records'
|
||||
};
|
||||
}
|
||||
if (DISCONNECTED.has(n)) {
|
||||
return {
|
||||
status: 'DISCONNECTED',
|
||||
suspected: false,
|
||||
disconnected: true,
|
||||
suspectedDetail: null,
|
||||
disconnectedDetail: disconnectedDetail(),
|
||||
message: 'Number is DISCONNECTED — found in MNRL records'
|
||||
};
|
||||
}
|
||||
return {
|
||||
status: 'CLEAN',
|
||||
suspected: false,
|
||||
disconnected: false,
|
||||
suspectedDetail: null,
|
||||
disconnectedDetail: null,
|
||||
message: 'Number is CLEAN — not found in DIP or MNRL records'
|
||||
};
|
||||
}
|
||||
|
||||
const server = http.createServer((req, res) => {
|
||||
const url = new URL(req.url, `http://${req.headers.host}`);
|
||||
|
||||
if (url.pathname !== '/api/v1/lookup/check') {
|
||||
res.writeHead(404, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify({ success: false, message: 'Not found', provider: PROVIDER }));
|
||||
return;
|
||||
}
|
||||
|
||||
const mobileNumber = url.searchParams.get('mobileNumber');
|
||||
if (!mobileNumber || !mobileNumber.trim()) {
|
||||
res.writeHead(400, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify({ success: false, message: 'mobileNumber is required', provider: PROVIDER }));
|
||||
return;
|
||||
}
|
||||
|
||||
const verdict = verdictFor(mobileNumber);
|
||||
const body = {
|
||||
success: true,
|
||||
message: verdict.message,
|
||||
timestamp: new Date().toISOString(),
|
||||
provider: PROVIDER,
|
||||
data: {
|
||||
mobileNumber: mobileNumber.trim(),
|
||||
status: verdict.status,
|
||||
suspected: verdict.suspected,
|
||||
disconnected: verdict.disconnected,
|
||||
suspectedDetail: verdict.suspectedDetail,
|
||||
disconnectedDetail: verdict.disconnectedDetail
|
||||
}
|
||||
};
|
||||
|
||||
console.log(`[${PROVIDER}] ${mobileNumber} -> ${verdict.status}`);
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify(body));
|
||||
});
|
||||
|
||||
server.listen(PORT, '127.0.0.1', () => {
|
||||
console.log(`${PROVIDER} listening on http://127.0.0.1:${PORT}`);
|
||||
console.log('This is NOT a real DoT DIP/MNRL service. Responses are invented.');
|
||||
console.log(`Set FINERACT_MOBILE_LOOKUP_BASE_URL=http://127.0.0.1:${PORT}`);
|
||||
});
|
||||
Reference in New Issue
Block a user