feat(ctsclearing): signature-verification gate and full NPCI field capture for inward cheques
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 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 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 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 Docker Builds / build (true, docker-compose.yml, mariadb) (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 Documentation build / build (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 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 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 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

Adds a manual signature-verification step to the inward CTS decision flow:
a new VERIFY_SIGNATURE command records the clerk's confirmation, and
InwardClearingItem.pass() now refuses to pass a cheque until signatureOk
is true — enforced server-side, not just a disabled UI button.

Fixes a real bug where ChequeLeaf.leafSerialNo collides across different
cheque books/series (by design — serials are only unique per stock lot),
which could resolve an inward item to the wrong account. NpciInwardPushService
now disambiguates using the drawer account number NPCI already sends
alongside the cheque number.

Also closes a completeness gap found by auditing the outward-CBS -> NPCI ->
inward-CBS pipeline: five fields NPCI sends on every instrument (drawer
account number, deposit account number, instrument type/description, drawee
bank name, per-check IQA breakdown) were read and discarded instead of
persisted — now saved via new columns and exposed on the read API.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Jaanu423
2026-07-22 12:30:07 +05:30
co-authored by Claude Sonnet 5
parent b433edfdfe
commit ab5666c0f4
14 changed files with 319 additions and 24 deletions
@@ -433,4 +433,6 @@
<include file="parts/0410_npci_inward_push_log.xml" relativeToChangelogFile="true"/>
<include file="parts/0411_inward_item_source_details.xml" relativeToChangelogFile="true"/>
<include file="parts/0412_activate_outward_clearing_batch_job.xml" relativeToChangelogFile="true"/>
<include file="parts/0413_inward_item_verify_signature_permission.xml" relativeToChangelogFile="true"/>
<include file="parts/0414_inward_item_full_source_details.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<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.1.xsd">
<!--
New command on INWARDCLEARINGITEM: the clerk's manual signature-verification decision, required
before an item can be PASSed (see InwardClearingItem.pass()). Mirrors the PASS/RETURN permission
rows seeded in 0395_clearing_permissions.xml.
-->
<changeSet id="0413-inward-item-verify-signature-permission" author="CBS" runOnChange="false">
<sql>
INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
SELECT 'portfolio', 'VERIFY_SIGNATURE_INWARDCLEARINGITEM', 'INWARDCLEARINGITEM', 'VERIFY_SIGNATURE', false
WHERE NOT EXISTS (SELECT 1 FROM m_permission WHERE code = 'VERIFY_SIGNATURE_INWARDCLEARINGITEM');
</sql>
</changeSet>
</databaseChangeLog>
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<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.1.xsd">
<!--
A field-by-field audit of the outward-CBS -> NPCI -> inward-CBS pipeline found several fields that
arrive in every NPCI instrument package but were silently dropped (read, or not even read, then
discarded) instead of being persisted on the inward item:
- drawerAccountNumberMasked: the drawee (this bank's own customer) account number, masked, that
NpciInwardPushService now also uses to disambiguate colliding cheque-leaf serials — previously
used transiently and discarded, now kept for audit trail.
- depositAccountNumber: the depositing (collecting-bank) customer's own account identifier.
- instrumentType / instrumentTypeDescription: the CTS instrument-type code carried on the wire.
- draweeBankName: the receiving bank's own name as asserted by the sender, for audit cross-check.
- iqaSubChecks: the per-check IQA breakdown (skew/noise/legibility/completeness), previously only
the rolled-up iqaStatus/iqaDetail survived.
Additive; safe no-op where applied.
-->
<changeSet id="0414-inward-item-full-source-details" author="CBS">
<preConditions onFail="MARK_RAN">
<and>
<tableExists tableName="m_inward_clearing_item"/>
<not><columnExists tableName="m_inward_clearing_item" columnName="drawer_account_number_masked"/></not>
</and>
</preConditions>
<addColumn tableName="m_inward_clearing_item">
<column name="drawer_account_number_masked" type="VARCHAR(40)"/>
<column name="deposit_account_number" type="VARCHAR(40)"/>
<column name="instrument_type" type="VARCHAR(10)"/>
<column name="instrument_type_description" type="VARCHAR(100)"/>
<column name="drawee_bank_name" type="VARCHAR(150)"/>
<column name="iqa_sub_checks" type="VARCHAR(300)"/>
</addColumn>
</changeSet>
</databaseChangeLog>