Add all CBS custom modules: KYC, Sanctions, RBI Feed, OpenProject, Mobile Lookup, Charges, Avro schemas

Includes all prior work not yet committed on this branch:
- KYC module (LincPay eKYC: PAN, Aadhaar OTP, GSTIN verification)
- Sanctions screening (UN Security Council consolidated list)
- RBI Feed integration with scheduled jobs
- OpenProject API integration
- Mobile lookup service
- Charge module enhancements (current account support)
- Client family member nominee fields
- Avro schema updates
- Liquibase migrations 0216-0224
- Postman collections for OpenProject, RBI Feeds, Sanctions
- SQL seed scripts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Aditya
2026-03-18 17:54:10 +05:30
co-authored by Claude Opus 4.6
parent 78f37257a7
commit ba5365d4af
102 changed files with 9757 additions and 18 deletions
+139
View File
@@ -0,0 +1,139 @@
-- =============================================================================
-- KYC Module – Table Creation Script (MySQL / MariaDB)
-- =============================================================================
-- DB Connection (from config/docker/env/fineract-common.env & mariadb.env):
-- Host : localhost (or 'db' inside Docker)
-- Port : 3306
-- Database : fineract_default ← tenant database (your actual data lives here)
-- Username : root
-- Password : skdcnwauicn2ucnaecasdsajdnizucawencascdca
--
-- Run command:
-- mysql -h localhost -P 3306 -u root -p'skdcnwauicn2ucnaecasdsajdnizucawencascdca' fineract_default < create_kyc_tables_mysql_mariadb.sql
-- =============================================================================
USE fineract_default;
-- =============================================================================
-- TABLE: m_client_kyc
-- One KYC record per client (enforced by UNIQUE on client_id).
-- Stores PAN, Aadhaar (masked), GSTIN, CKYCRR number, risk category,
-- lifecycle dates and audit fields.
-- =============================================================================
CREATE TABLE IF NOT EXISTS `m_client_kyc` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`client_id` BIGINT NOT NULL,
-- kyc_status : 100=PENDING | 200=IN_PROGRESS | 300=VERIFIED | 400=REJECTED | 500=EXPIRED
`kyc_status` SMALLINT NOT NULL DEFAULT 100,
-- kyc_type : 1=INDIVIDUAL | 2=NON_INDIVIDUAL
`kyc_type` SMALLINT NOT NULL,
-- risk_category : 1=LOW (re-KYC 10yr) | 2=MEDIUM (8yr) | 3=HIGH (2yr)
`risk_category` SMALLINT NOT NULL DEFAULT 1,
-- PAN (Permanent Account Number – Income Tax Dept)
-- Format: 5 uppercase letters + 4 digits + 1 uppercase letter e.g. ABCDE1234F
`pan_number` VARCHAR(10) NULL,
`pan_verified` TINYINT(1) NOT NULL DEFAULT 0,
`pan_verified_on` DATE NULL,
-- Aadhaar – ONLY masked form stored (last 4 digits visible) per UIDAI directive
-- e.g. XXXXXXXX1234
`aadhaar_number_masked` VARCHAR(12) NULL,
`aadhaar_verified` TINYINT(1) NOT NULL DEFAULT 0,
`aadhaar_verified_on` DATE NULL,
-- GSTIN (15-char GST Identification Number – mandatory for NON_INDIVIDUAL)
-- Format: 2-digit state code + 10-char PAN + 1 entity num + Z + check digit
`gstin_number` VARCHAR(15) NULL,
`gstin_verified` TINYINT(1) NOT NULL DEFAULT 0,
`gstin_verified_on` DATE NULL,
-- CKYCRR – Central KYC Records Registry number (issued by CERSAI, 14 digits)
`ckyc_number` VARCHAR(14) NULL,
-- Lifecycle timestamps
`initiated_on` DATE NULL,
`verified_on` DATE NULL,
`rejected_on` DATE NULL,
-- expiry_date computed as: verified_on + risk_category years offset
`expiry_date` DATE NULL,
`remarks` VARCHAR(500) NULL,
-- Audit fields (AbstractAuditableWithUTCDateTimeCustom)
`created_by` BIGINT NOT NULL,
`created_on_utc` DATETIME NOT NULL,
`last_modified_by` BIGINT NOT NULL,
`last_modified_on_utc` DATETIME NOT NULL,
`version` BIGINT NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY `uq_m_client_kyc_client_id` (`client_id`),
CONSTRAINT `FK_m_client_kyc_client_id`
FOREIGN KEY (`client_id`) REFERENCES `m_client` (`id`)
ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- =============================================================================
-- TABLE: m_client_kyc_verification_log
-- Immutable audit trail for every 3rd-party PAN / Aadhaar / GSTIN API call.
-- =============================================================================
CREATE TABLE IF NOT EXISTS `m_client_kyc_verification_log` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`kyc_id` BIGINT NOT NULL,
-- verification_type: PAN | AADHAAR | GSTIN
`verification_type` VARCHAR(20) NOT NULL,
-- verification_status: SUCCESS | FAILURE | PENDING | ERROR
`verification_status` VARCHAR(20) NOT NULL,
-- External reference id returned by the 3rd-party vendor API
`request_reference` VARCHAR(100) NULL,
-- Full raw JSON response from the vendor – stored for compliance audit
`api_response` TEXT NULL,
`remarks` VARCHAR(500) NULL,
-- Audit fields
`created_by` BIGINT NOT NULL,
`created_on_utc` DATETIME NOT NULL,
`last_modified_by` BIGINT NOT NULL,
`last_modified_on_utc` DATETIME NOT NULL,
`version` BIGINT NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
CONSTRAINT `FK_m_kyc_verification_log_kyc_id`
FOREIGN KEY (`kyc_id`) REFERENCES `m_client_kyc` (`id`)
ON DELETE CASCADE ON UPDATE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- =============================================================================
-- PERMISSIONS – Insert into m_permission
-- =============================================================================
INSERT IGNORE INTO `m_permission`
(`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`)
VALUES
('portfolio', 'READ_CLIENTKYC', 'CLIENTKYC', 'READ', 0),
('portfolio', 'CREATE_CLIENTKYC', 'CLIENTKYC', 'CREATE', 1),
('portfolio', 'UPDATE_CLIENTKYC', 'CLIENTKYC', 'UPDATE', 1),
('portfolio', 'VERIFY_CLIENTKYC', 'CLIENTKYC', 'VERIFY', 1),
('portfolio', 'REJECT_CLIENTKYC', 'CLIENTKYC', 'REJECT', 1);
-- =============================================================================
-- VERIFY CREATION
-- =============================================================================
SELECT 'Tables created:' AS info;
SHOW TABLES LIKE 'm_client_kyc%';
SELECT 'Permissions inserted:' AS info;
SELECT code, entity_name, action_name FROM m_permission WHERE entity_name = 'CLIENTKYC';
+155
View File
@@ -0,0 +1,155 @@
-- =============================================================================
-- KYC Module – Table Creation Script (PostgreSQL)
-- =============================================================================
-- DB Connection (from config/docker/env/postgresql.env & application.properties):
-- Host : localhost
-- Port : 5432
-- Database : fineract_default ← tenant database (your actual data lives here)
-- Username : postgres
-- Password : skdcnwauicn2ucnaecasdsajdnizucawencascdca
--
-- Run command:
-- psql -h localhost -p 5432 -U postgres -d fineract_default -f create_kyc_tables_postgresql.sql
--
-- (It will prompt for password: skdcnwauicn2ucnaecasdsajdnizucawencascdca)
-- =============================================================================
\connect fineract_default;
-- =============================================================================
-- TABLE: m_client_kyc
-- One KYC record per client (enforced by UNIQUE on client_id).
-- =============================================================================
CREATE TABLE IF NOT EXISTS m_client_kyc (
id BIGSERIAL NOT NULL,
client_id BIGINT NOT NULL,
-- kyc_status : 100=PENDING | 200=IN_PROGRESS | 300=VERIFIED | 400=REJECTED | 500=EXPIRED
kyc_status SMALLINT NOT NULL DEFAULT 100,
-- kyc_type : 1=INDIVIDUAL | 2=NON_INDIVIDUAL
kyc_type SMALLINT NOT NULL,
-- risk_category : 1=LOW (re-KYC 10yr) | 2=MEDIUM (8yr) | 3=HIGH (2yr)
risk_category SMALLINT NOT NULL DEFAULT 1,
-- PAN (Permanent Account Number – Income Tax Dept)
-- Format: 5 uppercase letters + 4 digits + 1 uppercase letter e.g. ABCDE1234F
pan_number VARCHAR(10),
pan_verified BOOLEAN NOT NULL DEFAULT FALSE,
pan_verified_on DATE,
-- Aadhaar – ONLY masked form stored (last 4 digits visible) per UIDAI directive
aadhaar_number_masked VARCHAR(12),
aadhaar_verified BOOLEAN NOT NULL DEFAULT FALSE,
aadhaar_verified_on DATE,
-- GSTIN (15-char GST Identification Number – mandatory for NON_INDIVIDUAL)
gstin_number VARCHAR(15),
gstin_verified BOOLEAN NOT NULL DEFAULT FALSE,
gstin_verified_on DATE,
-- CKYCRR – Central KYC Records Registry number (issued by CERSAI, 14 digits)
ckyc_number VARCHAR(14),
-- Lifecycle timestamps
initiated_on DATE,
verified_on DATE,
rejected_on DATE,
expiry_date DATE,
remarks VARCHAR(500),
-- Audit fields (AbstractAuditableWithUTCDateTimeCustom)
created_by BIGINT NOT NULL,
created_on_utc TIMESTAMP WITH TIME ZONE NOT NULL,
last_modified_by BIGINT NOT NULL,
last_modified_on_utc TIMESTAMP WITH TIME ZONE NOT NULL,
version BIGINT NOT NULL DEFAULT 0,
CONSTRAINT pk_m_client_kyc PRIMARY KEY (id),
CONSTRAINT uq_m_client_kyc_client_id UNIQUE (client_id),
CONSTRAINT fk_m_client_kyc_client_id
FOREIGN KEY (client_id) REFERENCES m_client(id)
ON DELETE RESTRICT ON UPDATE RESTRICT
);
COMMENT ON TABLE m_client_kyc IS 'RBI-mandated KYC record – one per client';
COMMENT ON COLUMN m_client_kyc.kyc_status IS '100=PENDING,200=IN_PROGRESS,300=VERIFIED,400=REJECTED,500=EXPIRED';
COMMENT ON COLUMN m_client_kyc.kyc_type IS '1=INDIVIDUAL, 2=NON_INDIVIDUAL';
COMMENT ON COLUMN m_client_kyc.risk_category IS '1=LOW(10yr), 2=MEDIUM(8yr), 3=HIGH(2yr) re-KYC period';
COMMENT ON COLUMN m_client_kyc.aadhaar_number_masked IS 'Masked Aadhaar: first 8 digits X, last 4 visible. Full number must NOT be stored per UIDAI directive.';
-- =============================================================================
-- TABLE: m_client_kyc_verification_log
-- Immutable audit trail for every 3rd-party API call.
-- =============================================================================
CREATE TABLE IF NOT EXISTS m_client_kyc_verification_log (
id BIGSERIAL NOT NULL,
kyc_id BIGINT NOT NULL,
-- verification_type: PAN | AADHAAR | GSTIN
verification_type VARCHAR(20) NOT NULL,
-- verification_status: SUCCESS | FAILURE | PENDING | ERROR
verification_status VARCHAR(20) NOT NULL,
request_reference VARCHAR(100),
api_response TEXT,
remarks VARCHAR(500),
-- Audit fields
created_by BIGINT NOT NULL,
created_on_utc TIMESTAMP WITH TIME ZONE NOT NULL,
last_modified_by BIGINT NOT NULL,
last_modified_on_utc TIMESTAMP WITH TIME ZONE NOT NULL,
version BIGINT NOT NULL DEFAULT 0,
CONSTRAINT pk_m_client_kyc_verification_log PRIMARY KEY (id),
CONSTRAINT fk_m_kyc_verification_log_kyc_id
FOREIGN KEY (kyc_id) REFERENCES m_client_kyc(id)
ON DELETE CASCADE ON UPDATE RESTRICT
);
COMMENT ON TABLE m_client_kyc_verification_log IS 'Audit log of all 3rd-party KYC API calls (PAN/Aadhaar/GSTIN)';
-- =============================================================================
-- PERMISSIONS
-- =============================================================================
INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
SELECT 'portfolio', 'READ_CLIENTKYC', 'CLIENTKYC', 'READ', FALSE
WHERE NOT EXISTS (SELECT 1 FROM m_permission WHERE code = 'READ_CLIENTKYC');
INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
SELECT 'portfolio', 'CREATE_CLIENTKYC', 'CLIENTKYC', 'CREATE', TRUE
WHERE NOT EXISTS (SELECT 1 FROM m_permission WHERE code = 'CREATE_CLIENTKYC');
INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
SELECT 'portfolio', 'UPDATE_CLIENTKYC', 'CLIENTKYC', 'UPDATE', TRUE
WHERE NOT EXISTS (SELECT 1 FROM m_permission WHERE code = 'UPDATE_CLIENTKYC');
INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
SELECT 'portfolio', 'VERIFY_CLIENTKYC', 'CLIENTKYC', 'VERIFY', TRUE
WHERE NOT EXISTS (SELECT 1 FROM m_permission WHERE code = 'VERIFY_CLIENTKYC');
INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
SELECT 'portfolio', 'REJECT_CLIENTKYC', 'CLIENTKYC', 'REJECT', TRUE
WHERE NOT EXISTS (SELECT 1 FROM m_permission WHERE code = 'REJECT_CLIENTKYC');
-- =============================================================================
-- VERIFY CREATION
-- =============================================================================
SELECT tablename AS "Tables created"
FROM pg_tables
WHERE schemaname = 'public'
AND tablename LIKE 'm_client_kyc%';
SELECT code, entity_name, action_name
FROM m_permission
WHERE entity_name = 'CLIENTKYC';
+521
View File
@@ -0,0 +1,521 @@
-- ============================================================
-- Fineract Sample Data Seed Script (PostgreSQL)
-- Database: fineract_default
-- Run with: psql -U postgres -d fineract_default -f seed_sample_data.sql
-- ============================================================
-- NOTE: Fineract typically bootstraps with:
-- m_office id=1 (Head Office), m_appuser id=1 (admin)
-- Run this AFTER Fineract has started at least once so
-- the base schema + default data exist.
-- ============================================================
BEGIN;
-- ============================================================
-- 1. OFFICES (id 2-5, Head Office id=1 already exists)
-- ============================================================
INSERT INTO m_office (id, parent_id, hierarchy, external_id, name, opening_date, created_by, created_on_utc, last_modified_by, last_modified_on_utc)
VALUES
(2, 1, '.1.2.', 'OFF-MUM-001', 'Mumbai Branch', '2024-01-15', 1, NOW(), 1, NOW()),
(3, 1, '.1.3.', 'OFF-DEL-001', 'Delhi Branch', '2024-02-01', 1, NOW(), 1, NOW()),
(4, 1, '.1.4.', 'OFF-BLR-001', 'Bangalore Branch', '2024-03-10', 1, NOW(), 1, NOW()),
(5, 2, '.1.2.5.', 'OFF-MUM-SUB', 'Mumbai Sub-Branch', '2024-06-01', 1, NOW(), 1, NOW())
ON CONFLICT (id) DO NOTHING;
SELECT setval('m_office_id_seq', GREATEST((SELECT MAX(id) FROM m_office), 5));
-- ============================================================
-- 2. STAFF (5 staff members across offices)
-- ============================================================
INSERT INTO m_staff (id, is_loan_officer, office_id, firstname, lastname, display_name, mobile_no, external_id, is_active, joining_date, email_address, created_by, created_on_utc, last_modified_by, last_modified_on_utc)
VALUES
(1, true, 2, 'Rajesh', 'Sharma', 'Sharma, Rajesh', '9876543210', 'STF-001', true, '2024-01-20', 'rajesh.sharma@cbs.in', 1, NOW(), 1, NOW()),
(2, true, 3, 'Priya', 'Patel', 'Patel, Priya', '9876543211', 'STF-002', true, '2024-02-10', 'priya.patel@cbs.in', 1, NOW(), 1, NOW()),
(3, true, 4, 'Amit', 'Kumar', 'Kumar, Amit', '9876543212', 'STF-003', true, '2024-03-15', 'amit.kumar@cbs.in', 1, NOW(), 1, NOW()),
(4, false, 2, 'Sneha', 'Reddy', 'Reddy, Sneha', '9876543213', 'STF-004', true, '2024-04-01', 'sneha.reddy@cbs.in', 1, NOW(), 1, NOW()),
(5, true, 5, 'Vikram', 'Singh', 'Singh, Vikram', '9876543214', 'STF-005', true, '2024-06-15', 'vikram.singh@cbs.in', 1, NOW(), 1, NOW())
ON CONFLICT (id) DO NOTHING;
SELECT setval('m_staff_id_seq', GREATEST((SELECT MAX(id) FROM m_staff), 5));
-- ============================================================
-- 3. CLIENTS (5 clients — 4 individuals, 1 entity)
-- ============================================================
INSERT INTO m_client (id, account_no, external_id, status_enum, activation_date, office_joining_date, office_id, staff_id,
firstname, middlename, lastname, fullname, display_name, mobile_no, is_staff,
date_of_birth, email_address, legal_form_enum,
submittedon_date, submittedon_userid, activatedon_userid,
created_by, created_on_utc, last_modified_by, last_modified_on_utc)
VALUES
(1, '000000001', 'CLI-IND-001', 300, '2024-04-01', '2024-04-01', 2, 1,
'Arun', NULL, 'Mehta', NULL, 'Arun Mehta', '9100000001', false,
'1990-05-15', 'arun.mehta@gmail.com', 1,
'2024-03-25', 1, 1,
1, NOW(), 1, NOW()),
(2, '000000002', 'CLI-IND-002', 300, '2024-04-10', '2024-04-10', 3, 2,
'Kavita', 'Devi', 'Joshi', NULL, 'Kavita Devi Joshi', '9100000002', false,
'1985-08-22', 'kavita.joshi@gmail.com', 1,
'2024-04-05', 1, 1,
1, NOW(), 1, NOW()),
(3, '000000003', 'CLI-IND-003', 300, '2024-05-01', '2024-05-01', 4, 3,
'Suresh', NULL, 'Iyer', NULL, 'Suresh Iyer', '9100000003', false,
'1978-12-10', 'suresh.iyer@yahoo.com', 1,
'2024-04-20', 1, 1,
1, NOW(), 1, NOW()),
(4, '000000004', 'CLI-IND-004', 300, '2024-06-01', '2024-06-01', 5, 5,
'Neha', NULL, 'Gupta', NULL, 'Neha Gupta', '9100000004', false,
'1995-03-30', 'neha.gupta@gmail.com', 1,
'2024-05-25', 1, 1,
1, NOW(), 1, NOW()),
-- Non-individual (Entity / Company) client
(5, '000000005', 'CLI-ENT-001', 300, '2024-07-01', '2024-07-01', 2, 4,
NULL, NULL, NULL, 'TechNova Solutions Pvt Ltd', 'TechNova Solutions Pvt Ltd', '9100000005', false,
NULL, 'info@technova.in', 2,
'2024-06-20', 1, 1,
1, NOW(), 1, NOW())
ON CONFLICT (id) DO NOTHING;
SELECT setval('m_client_id_seq', GREATEST((SELECT MAX(id) FROM m_client), 5));
-- ============================================================
-- 4. GROUPS (2 centers + 3 groups)
-- ============================================================
-- First ensure group levels exist (Fineract default: 1=Center, 2=Group)
INSERT INTO m_group_level (id, parent_id, super_parent, level_name, recursable, can_have_clients)
VALUES
(1, NULL, true, 'Center', true, false),
(2, 1, false, 'Group', false, true)
ON CONFLICT (id) DO NOTHING;
INSERT INTO m_group (id, external_id, status_enum, activation_date, office_id, staff_id, parent_id, level_id, display_name, hierarchy, account_no,
submittedon_date, submittedon_userid, activatedon_userid,
created_by, created_on_utc, last_modified_by, last_modified_on_utc)
VALUES
-- Centers (level_id=1)
(1, 'CTR-MUM-001', 300, '2024-04-01', 2, 1, NULL, 1, 'Mumbai Center 1', '.1.', 'G000000001',
'2024-03-25', 1, 1, 1, NOW(), 1, NOW()),
(2, 'CTR-DEL-001', 300, '2024-04-10', 3, 2, NULL, 1, 'Delhi Center 1', '.2.', 'G000000002',
'2024-04-05', 1, 1, 1, NOW(), 1, NOW()),
-- Groups under centers (level_id=2)
(3, 'GRP-MUM-001', 300, '2024-04-01', 2, 1, 1, 2, 'Mumbai SHG Group A', '.1.3.', 'G000000003',
'2024-03-25', 1, 1, 1, NOW(), 1, NOW()),
(4, 'GRP-MUM-002', 300, '2024-04-01', 2, 1, 1, 2, 'Mumbai SHG Group B', '.1.4.', 'G000000004',
'2024-03-25', 1, 1, 1, NOW(), 1, NOW()),
(5, 'GRP-DEL-001', 300, '2024-04-10', 3, 2, 2, 2, 'Delhi Mahila Group', '.2.5.', 'G000000005',
'2024-04-05', 1, 1, 1, NOW(), 1, NOW())
ON CONFLICT (id) DO NOTHING;
SELECT setval('m_group_id_seq', GREATEST((SELECT MAX(id) FROM m_group), 5));
-- Link clients to groups
INSERT INTO m_group_client (group_id, client_id)
VALUES
(3, 1), -- Arun → Mumbai SHG Group A
(3, 4), -- Neha → Mumbai SHG Group A
(4, 5), -- TechNova → Mumbai SHG Group B
(5, 2), -- Kavita → Delhi Mahila Group
(5, 3) -- Suresh → Delhi Mahila Group
ON CONFLICT DO NOTHING;
-- ============================================================
-- 5. SAVINGS PRODUCTS (4 products)
-- ============================================================
INSERT INTO m_savings_product (id, name, short_name, description, deposit_type_enum,
currency_code, currency_digits, currency_multiplesof,
nominal_annual_interest_rate, interest_compounding_period_enum,
interest_posting_period_enum, interest_calculation_type_enum,
interest_calculation_days_in_year_type_enum,
min_required_opening_balance, lockin_period_frequency, lockin_period_frequency_enum,
accounting_type, withdrawal_fee_for_transfer, allow_overdraft,
overdraft_limit, nominal_annual_interest_rate_overdraft,
min_overdraft_for_interest_calculation, enforce_min_required_balance,
min_required_balance, withhold_tax,
created_by, created_on_utc, last_modified_by, last_modified_on_utc)
VALUES
(1, 'Regular Savings Account', 'RESA', 'Basic savings account with 4% interest', 100,
'INR', 2, 1,
4.000000, 1, -- daily compounding
4, -- monthly posting
1, -- daily balance
365, -- 365 days/year
500.000000, NULL, NULL,
1, -- NONE accounting
true, false, NULL, 0, 0, false, NULL, false,
1, NOW(), 1, NOW()),
(2, 'Fixed Deposit 1 Year', 'FD1Y', '1-year FD at 7% p.a.', 200,
'INR', 2, 1,
7.000000, 4, -- quarterly compounding
4, -- monthly posting
1, 365,
10000.000000, 12, 2, -- 12 month lock-in
1, true, false, NULL, 0, 0, false, NULL, false,
1, NOW(), 1, NOW()),
(3, 'Jan Dhan Yojana Savings', 'JDYS', 'PMJDY zero-balance savings', 100,
'INR', 2, 1,
3.500000, 1, 4, 1, 365,
0.000000, NULL, NULL,
1, true, true, 10000.000000, 0, 0, false, NULL, false,
1, NOW(), 1, NOW()),
(4, 'Business Current Account', 'BUCA', 'Current account for businesses, no interest', 100,
'INR', 2, 1,
0.000000, 1, 4, 1, 365,
25000.000000, NULL, NULL,
1, true, true, 50000.000000, 0, 0, true, 10000.000000, false,
1, NOW(), 1, NOW())
ON CONFLICT (id) DO NOTHING;
SELECT setval('m_savings_product_id_seq', GREATEST((SELECT MAX(id) FROM m_savings_product), 4));
-- ============================================================
-- 6. SAVINGS ACCOUNTS (5 accounts linked to clients)
-- ============================================================
INSERT INTO m_savings_account (id, account_no, external_id, client_id, group_id, product_id, field_officer_id,
status_enum, sub_status_enum, account_type_enum, deposit_type_enum,
submittedon_date, submittedon_userid, approvedon_date, approvedon_userid,
activatedon_date, activatedon_userid,
currency_code, currency_digits, currency_multiplesof,
nominal_annual_interest_rate, interest_compounding_period_enum,
interest_posting_period_enum, interest_calculation_type_enum,
interest_calculation_days_in_year_type_enum,
min_required_opening_balance, withdrawal_fee_for_transfer,
allow_overdraft, overdraft_limit,
nominal_annual_interest_rate_overdraft, min_overdraft_for_interest_calculation,
account_balance_derived, enforce_min_required_balance,
total_deposits_derived, total_withdrawals_derived,
total_overdraft_interest_derived, version, withhold_tax,
created_by, created_on_utc, last_modified_by, last_modified_on_utc)
VALUES
-- Arun Mehta → Regular Savings
(1, 'SA000000001', 'SA-IND-001', 1, NULL, 1, 1,
300, 0, 1, 100,
'2024-04-01', 1, '2024-04-02', 1, '2024-04-02', 1,
'INR', 2, 1,
4.000000, 1, 4, 1, 365,
500.000000, true, false, NULL, 0, 0,
25000.000000, false,
30000.000000, 5000.000000, 0, 1, false,
1, NOW(), 1, NOW()),
-- Kavita Joshi → Regular Savings
(2, 'SA000000002', 'SA-IND-002', 2, NULL, 1, 2,
300, 0, 1, 100,
'2024-04-10', 1, '2024-04-11', 1, '2024-04-11', 1,
'INR', 2, 1,
4.000000, 1, 4, 1, 365,
500.000000, true, false, NULL, 0, 0,
15000.000000, false,
18000.000000, 3000.000000, 0, 1, false,
1, NOW(), 1, NOW()),
-- Suresh Iyer → Jan Dhan Yojana Savings
(3, 'SA000000003', 'SA-IND-003', 3, NULL, 3, 3,
300, 0, 1, 100,
'2024-05-01', 1, '2024-05-02', 1, '2024-05-02', 1,
'INR', 2, 1,
3.500000, 1, 4, 1, 365,
0.000000, true, true, 10000.000000, 0, 0,
2500.000000, false,
5000.000000, 2500.000000, 0, 1, false,
1, NOW(), 1, NOW()),
-- Neha Gupta → Fixed Deposit
(4, 'SA000000004', 'SA-IND-004', 4, NULL, 2, 5,
300, 0, 1, 200,
'2024-06-01', 1, '2024-06-02', 1, '2024-06-02', 1,
'INR', 2, 1,
7.000000, 4, 4, 1, 365,
10000.000000, true, false, NULL, 0, 0,
100000.000000, false,
100000.000000, 0.000000, 0, 1, false,
1, NOW(), 1, NOW()),
-- TechNova → Business Current Account
(5, 'SA000000005', 'SA-ENT-001', 5, NULL, 4, 4,
300, 0, 1, 100,
'2024-07-01', 1, '2024-07-02', 1, '2024-07-02', 1,
'INR', 2, 1,
0.000000, 1, 4, 1, 365,
25000.000000, true, true, 50000.000000, 0, 0,
350000.000000, true,
500000.000000, 150000.000000, 0, 1, false,
1, NOW(), 1, NOW())
ON CONFLICT (id) DO NOTHING;
SELECT setval('m_savings_account_id_seq', GREATEST((SELECT MAX(id) FROM m_savings_account), 5));
-- ============================================================
-- 7. LOAN PRODUCTS (2 products — needed before loans)
-- ============================================================
INSERT INTO m_product_loan (id, short_name, name, description,
fund_id, currency_code, currency_digits, currency_multiplesof,
principal_amount, min_principal_amount, max_principal_amount,
arrearstolerance_amount,
nominal_interest_rate_per_period, interest_period_frequency_enum,
annual_nominal_interest_rate, interest_method_enum,
interest_calculated_in_period_enum, allow_partial_period_interest_calcualtion,
repay_every, repayment_period_frequency_enum, number_of_repayments,
min_number_of_repayments, max_number_of_repayments,
amortization_method_enum,
accounting_type, loan_transaction_strategy_id,
grace_on_arrears_ageing,
days_in_month_enum, days_in_year_enum,
interest_recalculation_enabled, is_equal_amortization,
can_define_fixed_emi_amount,
created_by, created_on_utc, last_modified_by, last_modified_on_utc)
VALUES
(1, 'MSME', 'MSME Business Loan', 'Loan for small businesses up to 10L at 12% p.a.',
NULL, 'INR', 2, 1,
500000.000000, 50000.000000, 1000000.000000,
NULL,
1.000000, 2, -- 1% per month
12.000000, 0, -- flat interest
1, false,
1, 2, 12, -- monthly repay, 12 installments
6, 24,
1, -- equal installments
1, NULL, NULL,
1, 1, false, false, false,
1, NOW(), 1, NOW()),
(2, 'PERL', 'Personal Loan', 'Personal loan up to 5L at 14% p.a.',
NULL, 'INR', 2, 1,
200000.000000, 25000.000000, 500000.000000,
NULL,
14.000000, 3, -- 14% per year
14.000000, 1, -- declining balance
1, false,
1, 2, 24, -- monthly repay, 24 installments
6, 36,
1, 1, NULL, NULL,
1, 1, false, false, false,
1, NOW(), 1, NOW())
ON CONFLICT (id) DO NOTHING;
SELECT setval('m_product_loan_id_seq', GREATEST((SELECT MAX(id) FROM m_product_loan), 2));
-- ============================================================
-- 8. LOANS (4 loans for clients)
-- ============================================================
INSERT INTO m_loan (id, account_no, external_id, client_id, group_id, product_id,
loan_officer_id, loan_status_id, loan_type_enum,
currency_code, currency_digits, currency_multiplesof,
principal_amount_proposed, principal_amount, approved_principal, net_disbursal_amount,
nominal_interest_rate_per_period, interest_period_frequency_enum,
annual_nominal_interest_rate, interest_method_enum,
interest_calculated_in_period_enum, allow_partial_period_interest_calcualtion,
term_frequency, term_period_frequency_enum, repay_every, repayment_period_frequency_enum,
number_of_repayments, amortization_method_enum,
submittedon_date, submittedon_userid,
approvedon_date, approvedon_userid,
expected_disbursedon_date, disbursedon_date, disbursedon_userid,
expected_maturedon_date,
principal_disbursed_derived, principal_outstanding_derived,
total_expected_repayment_derived, total_outstanding_derived,
interest_rate_differential, days_in_month_enum, days_in_year_enum,
interest_recalculation_enabled, is_npa, is_topup, is_equal_amortization,
version,
created_by, created_on_utc, last_modified_by, last_modified_on_utc)
VALUES
-- Arun Mehta → MSME Loan (Active/Disbursed, status=300)
(1, 'LN000000001', 'LN-IND-001', 1, NULL, 1,
1, 300, 1,
'INR', 2, 1,
500000.000000, 500000.000000, 500000.000000, 500000.000000,
1.000000, 2, 12.000000, 0, 1, false,
12, 2, 1, 2, 12, 1,
'2024-05-01', 1, '2024-05-05', 1,
'2024-05-10', '2024-05-10', 1,
'2025-05-10',
500000.000000, 350000.000000,
560000.000000, 410000.000000,
0, 1, 1, false, false, false, false, 1,
1, NOW(), 1, NOW()),
-- Kavita Joshi → Personal Loan (Active/Disbursed, status=300)
(2, 'LN000000002', 'LN-IND-002', 2, NULL, 2,
2, 300, 1,
'INR', 2, 1,
200000.000000, 200000.000000, 200000.000000, 200000.000000,
14.000000, 3, 14.000000, 1, 1, false,
24, 2, 1, 2, 24, 1,
'2024-05-15', 1, '2024-05-20', 1,
'2024-06-01', '2024-06-01', 1,
'2026-06-01',
200000.000000, 160000.000000,
228000.000000, 188000.000000,
0, 1, 1, false, false, false, false, 1,
1, NOW(), 1, NOW()),
-- Suresh Iyer → MSME Loan (Approved not yet disbursed, status=200)
(3, 'LN000000003', 'LN-IND-003', 3, NULL, 1,
3, 200, 1,
'INR', 2, 1,
300000.000000, 300000.000000, 300000.000000, 300000.000000,
1.000000, 2, 12.000000, 0, 1, false,
12, 2, 1, 2, 12, 1,
'2024-07-01', 1, '2024-07-10', 1,
'2024-07-15', NULL, NULL,
'2025-07-15',
0, 0,
0, 0,
0, 1, 1, false, false, false, false, 1,
1, NOW(), 1, NOW()),
-- TechNova → MSME Loan (Active/Disbursed, status=300)
(4, 'LN000000004', 'LN-ENT-001', 5, NULL, 1,
4, 300, 1,
'INR', 2, 1,
1000000.000000, 1000000.000000, 1000000.000000, 1000000.000000,
1.000000, 2, 12.000000, 0, 1, false,
12, 2, 1, 2, 12, 1,
'2024-08-01', 1, '2024-08-05', 1,
'2024-08-10', '2024-08-10', 1,
'2025-08-10',
1000000.000000, 750000.000000,
1120000.000000, 870000.000000,
0, 1, 1, false, false, false, false, 1,
1, NOW(), 1, NOW())
ON CONFLICT (id) DO NOTHING;
SELECT setval('m_loan_id_seq', GREATEST((SELECT MAX(id) FROM m_loan), 4));
-- ============================================================
-- 9. CLIENT KYC (5 KYC records — one per client)
-- ============================================================
INSERT INTO m_client_kyc (id, client_id, kyc_status, kyc_type, risk_category,
pan_number, pan_verified, pan_verified_on,
aadhaar_number_masked, aadhaar_verified, aadhaar_verified_on,
gstin_number, gstin_verified, gstin_verified_on,
ckyc_number, initiated_on, verified_on, rejected_on, expiry_date, remarks,
created_by, created_on_utc, last_modified_by, last_modified_on_utc)
VALUES
-- Arun Mehta — Fully verified individual, LOW risk
(1, 1, 300, 1, 1,
'ABCPM1234A', true, '2024-04-02',
'XXXX XXXX 5678', true, '2024-04-03',
NULL, false, NULL,
'CKYC00001234', '2024-04-01', '2024-04-03', NULL, '2034-04-03', 'KYC completed via LincPay eKYC',
1, NOW(), 1, NOW()),
-- Kavita Joshi — PAN verified, Aadhaar pending, IN_PROGRESS
(2, 2, 200, 1, 2,
'BCDPJ5678B', true, '2024-04-11',
NULL, false, NULL,
NULL, false, NULL,
NULL, '2024-04-10', NULL, NULL, NULL, 'Aadhaar OTP verification pending',
1, NOW(), 1, NOW()),
-- Suresh Iyer — Fully verified individual, MEDIUM risk
(3, 3, 300, 1, 2,
'CDEPI9012C', true, '2024-05-02',
'XXXX XXXX 1234', true, '2024-05-03',
NULL, false, NULL,
'CKYC00005678', '2024-05-01', '2024-05-03', NULL, '2032-05-03', 'KYC completed — medium risk due to PEP flag',
1, NOW(), 1, NOW()),
-- Neha Gupta — PENDING (just initiated)
(4, 4, 100, 1, 1,
NULL, false, NULL,
NULL, false, NULL,
NULL, false, NULL,
NULL, '2024-06-01', NULL, NULL, NULL, 'KYC initiated, documents pending',
1, NOW(), 1, NOW()),
-- TechNova Solutions — Non-individual, verified with GSTIN, HIGH risk
(5, 5, 300, 2, 3,
'AABCT1234E', true, '2024-07-02',
NULL, false, NULL,
'27AABCT1234E1Z5', true, '2024-07-03',
'CKYC00009999', '2024-07-01', '2024-07-03', NULL, '2026-07-03', 'Non-individual KYC via GSTIN + PAN. High risk — new entity.',
1, NOW(), 1, NOW())
ON CONFLICT (id) DO NOTHING;
SELECT setval('m_client_kyc_id_seq', GREATEST((SELECT MAX(id) FROM m_client_kyc), 5));
-- ============================================================
-- 10. KYC VERIFICATION LOG (audit trail of eKYC API calls)
-- ============================================================
INSERT INTO m_client_kyc_verification_log (id, kyc_id, verification_type, verification_status,
request_reference, api_response, remarks,
created_by, created_on_utc, last_modified_by, last_modified_on_utc)
VALUES
-- Arun's PAN verification
(1, 1, 'PAN', 'SUCCESS',
'LNCP-PAN-20240402-001', '{"status":"success","pan":"ABCPM1234A","name":"ARUN MEHTA","valid":true}',
'PAN verified via LincPay',
1, '2024-04-02 10:30:00+05:30', 1, '2024-04-02 10:30:00+05:30'),
-- Arun's Aadhaar OTP generation
(2, 1, 'AADHAAR', 'SUCCESS',
'LNCP-AAD-20240403-001', '{"status":"success","ref_number":"AAD-REF-12345","message":"OTP sent"}',
'Aadhaar OTP sent successfully',
1, '2024-04-03 11:00:00+05:30', 1, '2024-04-03 11:00:00+05:30'),
-- Arun's Aadhaar OTP verification
(3, 1, 'AADHAAR', 'SUCCESS',
'LNCP-AAD-20240403-002', '{"status":"success","aadhaar_last4":"5678","name":"Arun Mehta","verified":true}',
'Aadhaar verified via OTP',
1, '2024-04-03 11:05:00+05:30', 1, '2024-04-03 11:05:00+05:30'),
-- Kavita's PAN verification
(4, 2, 'PAN', 'SUCCESS',
'LNCP-PAN-20240411-001', '{"status":"success","pan":"BCDPJ5678B","name":"KAVITA JOSHI","valid":true}',
'PAN verified via LincPay',
1, '2024-04-11 14:20:00+05:30', 1, '2024-04-11 14:20:00+05:30'),
-- Kavita's Aadhaar OTP — FAILED (wrong number)
(5, 2, 'AADHAAR', 'FAILURE',
'LNCP-AAD-20240412-001', '{"status":"failure","error_code":"INVALID_AADHAAR","message":"Invalid Aadhaar number"}',
'Aadhaar verification failed — invalid number provided',
1, '2024-04-12 09:15:00+05:30', 1, '2024-04-12 09:15:00+05:30'),
-- Suresh's PAN verification
(6, 3, 'PAN', 'SUCCESS',
'LNCP-PAN-20240502-001', '{"status":"success","pan":"CDEPI9012C","name":"SURESH IYER","valid":true}',
'PAN verified',
1, '2024-05-02 16:00:00+05:30', 1, '2024-05-02 16:00:00+05:30'),
-- Suresh's Aadhaar OTP + verify
(7, 3, 'AADHAAR', 'SUCCESS',
'LNCP-AAD-20240503-001', '{"status":"success","aadhaar_last4":"1234","name":"Suresh Iyer","verified":true}',
'Aadhaar verified via OTP',
1, '2024-05-03 10:00:00+05:30', 1, '2024-05-03 10:00:00+05:30'),
-- TechNova's PAN verification
(8, 5, 'PAN', 'SUCCESS',
'LNCP-PAN-20240702-001', '{"status":"success","pan":"AABCT1234E","name":"TECHNOVA SOLUTIONS PVT LTD","valid":true}',
'Company PAN verified',
1, '2024-07-02 11:30:00+05:30', 1, '2024-07-02 11:30:00+05:30'),
-- TechNova's GSTIN verification
(9, 5, 'GSTIN', 'SUCCESS',
'LNCP-GST-20240703-001', '{"status":"success","gstin":"27AABCT1234E1Z5","trade_name":"TechNova Solutions","valid":true,"active":true}',
'GSTIN verified via LincPay',
1, '2024-07-03 12:00:00+05:30', 1, '2024-07-03 12:00:00+05:30')
ON CONFLICT (id) DO NOTHING;
SELECT setval('m_client_kyc_verification_log_id_seq', GREATEST((SELECT MAX(id) FROM m_client_kyc_verification_log), 9));
COMMIT;
-- ============================================================
-- Summary of inserted data:
-- ============================================================
-- m_office : 4 new (Mumbai, Delhi, Bangalore, Mumbai Sub)
-- m_staff : 5 staff (3 loan officers, 1 ops, 1 sub-branch)
-- m_client : 5 clients (4 individuals + 1 company)
-- m_group / m_group_level : 2 centers + 3 SHG groups
-- m_savings_product : 4 products (Regular, FD, JDYS, Current)
-- m_savings_account : 5 accounts
-- m_product_loan : 2 products (MSME, Personal)
-- m_loan : 4 loans (2 active, 1 approved, 1 entity)
-- m_client_kyc : 5 KYC records (3 verified, 1 in-progress, 1 pending)
-- m_client_kyc_verification_log : 9 API audit log entries
-- ============================================================