From 14973dfd5e0971cddd89ad1f6e0098387e459017 Mon Sep 17 00:00:00 2001 From: Sonali Likhitkar Date: Mon, 12 Oct 2026 15:50:29 +0530 Subject: [PATCH] feat(delinquency): add maker-checker for Delinquency Ranges and Buckets Range/bucket create, update and delete now route through the standard command-source approval pipeline, since a bucket drives the SMA/NPA classification of every loan product linked to it. Co-Authored-By: Claude Sonnet 5 --- .../service/CommandSourceService.java | 2 + .../db/changelog/tenant/changelog-tenant.xml | 1 + .../0596_enable_delinquency_maker_checker.xml | 111 ++++++++++++++++++ 3 files changed, 114 insertions(+) create mode 100644 fineract-provider/src/main/resources/db/changelog/tenant/parts/0596_enable_delinquency_maker_checker.xml diff --git a/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandSourceService.java b/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandSourceService.java index 3b12899f3..54f428ea5 100644 --- a/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandSourceService.java +++ b/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandSourceService.java @@ -158,6 +158,8 @@ public class CommandSourceService { if ("GLACCOUNT".equalsIgnoreCase(commandSource.getEntityName()) || "CBSBASEINTERESTRATE".equalsIgnoreCase(commandSource.getEntityName()) || "LOANBASEINTERESTRATE".equalsIgnoreCase(commandSource.getEntityName()) + || "DELINQUENCY_BUCKET".equalsIgnoreCase(commandSource.getEntityName()) + || "DELINQUENCY_RANGE".equalsIgnoreCase(commandSource.getEntityName()) || "CHARGE".equalsIgnoreCase(commandSource.getEntityName()) || "LOANPRODUCT".equalsIgnoreCase(commandSource.getEntityName()) || "SAVINGSPRODUCT".equalsIgnoreCase(commandSource.getEntityName()) diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml index 9fa49d704..e05536f6c 100644 --- a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml +++ b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml @@ -621,4 +621,5 @@ + diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0596_enable_delinquency_maker_checker.xml b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0596_enable_delinquency_maker_checker.xml new file mode 100644 index 000000000..72f8d56b9 --- /dev/null +++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0596_enable_delinquency_maker_checker.xml @@ -0,0 +1,111 @@ + + + + + + + + ANY + + UPDATE m_permission + SET can_maker_checker = TRUE + WHERE code IN ('CREATE_DELINQUENCY_RANGE', 'UPDATE_DELINQUENCY_RANGE', 'DELETE_DELINQUENCY_RANGE', + 'CREATE_DELINQUENCY_BUCKET', 'UPDATE_DELINQUENCY_BUCKET', 'DELETE_DELINQUENCY_BUCKET'); + + INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker) + SELECT 'organisation', v.code, v.entity_name, v.action_name, false + FROM ( + SELECT 'CREATE_DELINQUENCY_RANGE_CHECKER' AS code, 'DELINQUENCY_RANGE' AS entity_name, 'CREATE_CHECKER' AS action_name + UNION ALL SELECT 'UPDATE_DELINQUENCY_RANGE_CHECKER', 'DELINQUENCY_RANGE', 'UPDATE_CHECKER' + UNION ALL SELECT 'DELETE_DELINQUENCY_RANGE_CHECKER', 'DELINQUENCY_RANGE', 'DELETE_CHECKER' + UNION ALL SELECT 'CREATE_DELINQUENCY_BUCKET_CHECKER', 'DELINQUENCY_BUCKET', 'CREATE_CHECKER' + UNION ALL SELECT 'UPDATE_DELINQUENCY_BUCKET_CHECKER', 'DELINQUENCY_BUCKET', 'UPDATE_CHECKER' + UNION ALL SELECT 'DELETE_DELINQUENCY_BUCKET_CHECKER', 'DELINQUENCY_BUCKET', 'DELETE_CHECKER' + ) v + WHERE NOT EXISTS (SELECT 1 FROM m_permission p WHERE p.code = v.code); + + + + + ANY + + -- Super user: maker + checker for all six commands. + INSERT INTO m_role_permission (role_id, permission_id) + SELECT r.id, p.id + FROM m_role r + CROSS JOIN m_permission p + WHERE r.name = 'Super user' + AND p.entity_name IN ('DELINQUENCY_RANGE', 'DELINQUENCY_BUCKET') + AND p.action_name IN ('CREATE', 'UPDATE', 'DELETE', 'CREATE_CHECKER', 'UPDATE_CHECKER', 'DELETE_CHECKER') + AND NOT EXISTS ( + SELECT 1 FROM m_role_permission rp + WHERE rp.role_id = r.id AND rp.permission_id = p.id + ); + + -- bankadmin user's role(s): maker + checker for all six commands. + INSERT INTO m_role_permission (role_id, permission_id) + SELECT DISTINCT ur.role_id, p.id + FROM m_appuser u + JOIN m_appuser_role ur ON ur.appuser_id = u.id + CROSS JOIN m_permission p + WHERE u.username = 'bankadmin' + AND p.entity_name IN ('DELINQUENCY_RANGE', 'DELINQUENCY_BUCKET') + AND p.action_name IN ('CREATE', 'UPDATE', 'DELETE', 'CREATE_CHECKER', 'UPDATE_CHECKER', 'DELETE_CHECKER') + AND NOT EXISTS ( + SELECT 1 FROM m_role_permission rp + WHERE rp.role_id = ur.role_id AND rp.permission_id = p.id + ); + + -- Every other role loses UPDATE / DELETE on ranges and buckets (and holds no checker permission). + DELETE FROM m_role_permission + WHERE permission_id IN ( + SELECT id FROM m_permission + WHERE entity_name IN ('DELINQUENCY_RANGE', 'DELINQUENCY_BUCKET') + AND action_name IN ('UPDATE', 'DELETE', 'CREATE_CHECKER', 'UPDATE_CHECKER', 'DELETE_CHECKER') + ) + AND role_id NOT IN ( + SELECT id FROM m_role WHERE name = 'Super user' + UNION + SELECT ur.role_id + FROM m_appuser u + JOIN m_appuser_role ur ON ur.appuser_id = u.id + WHERE u.username = 'bankadmin' + ); + + + +