From 53b6a94bf8bd4dc9ba4bcf8b4077827f07386002 Mon Sep 17 00:00:00 2001 From: Jaanu423 Date: Wed, 10 Jun 2026 11:17:32 +0530 Subject: [PATCH] fix(cashier): fix GL account search SQL bug, running balance, and add CASHIER role permissions - Fix searchParam SQL syntax: parameterized LIKE with %value% instead of literal %?% - Fix organizationRunningBalance: correlated subquery for latest journal entry (ORDER BY id DESC LIMIT 1) - Migration 0317: grant READ_GLACCOUNT, READ_LOAN, READ_SHAREACCOUNT to CASHIER role Co-Authored-By: Claude Sonnet 4.6 --- .../GLAccountReadPlatformServiceImpl.java | 547 +++++++++--------- .../db/changelog/tenant/changelog-tenant.xml | 1 + ...cashier_gl_loan_share_read_permissions.xml | 49 ++ 3 files changed, 325 insertions(+), 272 deletions(-) create mode 100644 fineract-provider/src/main/resources/db/changelog/tenant/parts/0317_grant_cashier_gl_loan_share_read_permissions.xml diff --git a/fineract-accounting/src/main/java/org/apache/fineract/accounting/glaccount/service/GLAccountReadPlatformServiceImpl.java b/fineract-accounting/src/main/java/org/apache/fineract/accounting/glaccount/service/GLAccountReadPlatformServiceImpl.java index 30783e53d..12ec205e3 100644 --- a/fineract-accounting/src/main/java/org/apache/fineract/accounting/glaccount/service/GLAccountReadPlatformServiceImpl.java +++ b/fineract-accounting/src/main/java/org/apache/fineract/accounting/glaccount/service/GLAccountReadPlatformServiceImpl.java @@ -1,272 +1,275 @@ -/** - * 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. - */ -package org.apache.fineract.accounting.glaccount.service; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.Arrays; -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.apache.commons.lang3.StringUtils; -import org.apache.fineract.accounting.common.AccountingEnumerations; -import org.apache.fineract.accounting.glaccount.data.GLAccountData; -import org.apache.fineract.accounting.glaccount.data.GLAccountDataForLookup; -import org.apache.fineract.accounting.glaccount.domain.GLAccountType; -import org.apache.fineract.accounting.glaccount.domain.GLAccountUsage; -import org.apache.fineract.accounting.glaccount.exception.GLAccountInvalidClassificationException; -import org.apache.fineract.accounting.glaccount.exception.GLAccountNotFoundException; -import org.apache.fineract.accounting.journalentry.data.JournalEntryAssociationParametersData; -import org.apache.fineract.infrastructure.codes.data.CodeValueData; -import org.apache.fineract.infrastructure.core.data.EnumOptionData; -import org.apache.fineract.infrastructure.core.domain.JdbcSupport; -import org.springframework.dao.EmptyResultDataAccessException; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.RowMapper; -import org.springframework.stereotype.Service; - -@Service -@RequiredArgsConstructor -public class GLAccountReadPlatformServiceImpl implements GLAccountReadPlatformService { - - private static final String NAME_DECORATED_BASE_ON_HIERARCHY = "concat(substring('........................................', 1, ((LENGTH(hierarchy) - LENGTH(REPLACE(hierarchy, '.', '')) - 1) * 4)), name)"; - - private final JdbcTemplate jdbcTemplate; - - private static final String SQL_AND = " and "; - - private static final class GLAccountMapper implements RowMapper { - - private final JournalEntryAssociationParametersData associationParametersData; - - GLAccountMapper(final JournalEntryAssociationParametersData associationParametersData) { - if (associationParametersData == null) { - this.associationParametersData = new JournalEntryAssociationParametersData(); - } else { - this.associationParametersData = associationParametersData; - } - } - - public String schema() { - StringBuilder sb = new StringBuilder(); - sb.append( - " gl.id as id, name as name, parent_id as parentId, gl_code as glCode, disabled as disabled, manual_journal_entries_allowed as manualEntriesAllowed, ") - .append("classification_enum as classification, account_usage as accountUsage, gl.description as description, ") - .append(NAME_DECORATED_BASE_ON_HIERARCHY).append(" as nameDecorated, ") - .append("cv.id as codeId, cv.code_value as codeValue "); - if (this.associationParametersData.isRunningBalanceRequired()) { - sb.append(",gl_j.organization_running_balance as organizationRunningBalance "); - } - sb.append("from acc_gl_account gl left join m_code_value cv on tag_id=cv.id "); - if (this.associationParametersData.isRunningBalanceRequired()) { - sb.append("left outer Join acc_gl_journal_entry gl_j on gl_j.account_id = gl.id"); - } - return sb.toString(); - } - - @Override - public GLAccountData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { - - final Long id = rs.getLong("id"); - final String name = rs.getString("name"); - final Long parentId = JdbcSupport.getLong(rs, "parentId"); - final String glCode = rs.getString("glCode"); - final boolean disabled = rs.getBoolean("disabled"); - final boolean manualEntriesAllowed = rs.getBoolean("manualEntriesAllowed"); - final int accountTypeId = JdbcSupport.getInteger(rs, "classification"); - final EnumOptionData accountType = AccountingEnumerations.gLAccountType(accountTypeId); - final int usageId = JdbcSupport.getInteger(rs, "accountUsage"); - final EnumOptionData usage = AccountingEnumerations.gLAccountUsage(usageId); - final String description = rs.getString("description"); - final String nameDecorated = rs.getString("nameDecorated"); - final Long codeId = rs.wasNull() ? null : rs.getLong("codeId"); - final String codeValue = rs.getString("codeValue"); - final CodeValueData tagId = CodeValueData.instance(codeId, codeValue); - Long organizationRunningBalance = null; - if (associationParametersData.isRunningBalanceRequired()) { - organizationRunningBalance = rs.getLong("organizationRunningBalance"); - } - return new GLAccountData().setId(id).setName(name).setParentId(parentId).setGlCode(glCode).setDisabled(disabled) - .setManualEntriesAllowed(manualEntriesAllowed).setType(accountType).setUsage(usage).setDescription(description) - .setNameDecorated(nameDecorated).setTagId(tagId).setOrganizationRunningBalance(organizationRunningBalance); - } - } - - @Override - public List retrieveAllGLAccounts(final Integer accountClassification, final String searchParam, final Integer usage, - final Boolean manualTransactionsAllowed, final Boolean disabled, - JournalEntryAssociationParametersData associationParametersData) { - if (accountClassification != null && !checkValidGLAccountType(accountClassification)) { - throw new GLAccountInvalidClassificationException(accountClassification); - } - - if (usage != null && !checkValidGLAccountUsage(usage)) { - throw new GLAccountInvalidClassificationException(accountClassification); - } - - final GLAccountMapper rm = new GLAccountMapper(associationParametersData); - String sql = "select " + rm.schema(); - // append SQL statement for fetching account totals - if (associationParametersData != null && associationParametersData.isRunningBalanceRequired()) { - sql = sql + " and gl_j.id in (select t1.id from (select t2.account_id, max(t2.id) as id from " - + "(select id, max(entry_date) as entry_date, account_id from acc_gl_journal_entry where is_running_balance_calculated = true " - + "group by account_id desc, id) t3 inner join acc_gl_journal_entry t2 on t2.account_id = t3.account_id and t2.entry_date = t3.entry_date " - + "group by t2.account_id desc) t1)"; - } - final Object[] parameterArray = new Object[3]; - int arrayPos = 0; - boolean filtersPresent = false; - if ((accountClassification != null) || StringUtils.isNotBlank(searchParam) || (usage != null) || (manualTransactionsAllowed != null) - || (disabled != null)) { - filtersPresent = true; - sql += " where"; - } - - if (filtersPresent) { - boolean firstWhereConditionAdded = false; - if (accountClassification != null) { - sql += " classification_enum = ?"; - parameterArray[arrayPos] = accountClassification.shortValue(); - arrayPos = arrayPos + 1; - firstWhereConditionAdded = true; - } - if (StringUtils.isNotBlank(searchParam)) { - if (firstWhereConditionAdded) { - sql += SQL_AND; - } - sql += " ( name like %?% or gl_code like %?% )"; - parameterArray[arrayPos] = searchParam; - arrayPos = arrayPos + 1; - parameterArray[arrayPos] = searchParam; - arrayPos = arrayPos + 1; - firstWhereConditionAdded = true; - } - if (usage != null) { - if (firstWhereConditionAdded) { - sql += SQL_AND; - } - if (GLAccountUsage.HEADER.getValue().equals(usage)) { - sql += " account_usage = 2 "; - } else if (GLAccountUsage.DETAIL.getValue().equals(usage)) { - sql += " account_usage = 1 "; - } - firstWhereConditionAdded = true; - } - if (manualTransactionsAllowed != null) { - if (firstWhereConditionAdded) { - sql += SQL_AND; - } - - sql += " manual_journal_entries_allowed = " + manualTransactionsAllowed; - firstWhereConditionAdded = true; - } - if (disabled != null) { - if (firstWhereConditionAdded) { - sql += SQL_AND; - } - - sql += " disabled = " + disabled; - } - } - - sql += " ORDER BY gl_code ASC"; - - final Object[] finalObjectArray = Arrays.copyOf(parameterArray, arrayPos); - return this.jdbcTemplate.query(sql, rm, (Object[]) finalObjectArray);// NOSONAR - } - - @Override - public GLAccountData retrieveGLAccountById(final long glAccountId, JournalEntryAssociationParametersData associationParametersData) { - try { - final GLAccountMapper rm = new GLAccountMapper(associationParametersData); - final StringBuilder sql = new StringBuilder(); - sql.append("select ").append(rm.schema()); - sql.append(" where gl.id = ?"); - if (associationParametersData.isRunningBalanceRequired()) { - sql.append(" and gl_j.is_running_balance_calculated = true ") - .append(" ORDER BY gl_j.entry_date DESC,gl_j.id DESC LIMIT 1"); - } - - return this.jdbcTemplate.queryForObject(sql.toString(), rm, new Object[] { glAccountId }); - } catch (final EmptyResultDataAccessException e) { - throw new GLAccountNotFoundException(glAccountId, e); - } - } - - @Override - public List retrieveAllEnabledDetailGLAccounts(final GLAccountType accountType) { - return retrieveAllGLAccounts(accountType.getValue(), null, GLAccountUsage.DETAIL.getValue(), null, false, - new JournalEntryAssociationParametersData()); - } - - @Override - public List retrieveAllEnabledDetailGLAccounts() { - return retrieveAllGLAccounts(null, null, GLAccountUsage.DETAIL.getValue(), null, false, - new JournalEntryAssociationParametersData()); - } - - private static boolean checkValidGLAccountType(final int type) { - for (final GLAccountType accountType : GLAccountType.values()) { - if (accountType.getValue().equals(type)) { - return true; - } - } - return false; - } - - private static boolean checkValidGLAccountUsage(final int type) { - for (final GLAccountUsage accountUsage : GLAccountUsage.values()) { - if (accountUsage.getValue().equals(type)) { - return true; - } - } - return false; - } - - @Override - public GLAccountData retrieveNewGLAccountDetails(final Integer type) { - return GLAccountData.sensibleDefaultsForNewGLAccountCreation(type); - } - - @Override - public List retrieveAllEnabledHeaderGLAccounts(final GLAccountType accountType) { - return retrieveAllGLAccounts(accountType.getValue(), null, GLAccountUsage.HEADER.getValue(), null, false, - new JournalEntryAssociationParametersData()); - } - - @Override - public List retrieveAccountsByTagId(final Long ruleId, final Integer transactionType) { - final GLAccountDataLookUpMapper mapper = new GLAccountDataLookUpMapper(); - final String sql = "Select " + GLAccountDataLookUpMapper.LOOKUP_SCHEMA + " where rule.id=? and tags.acc_type_enum=?"; - return this.jdbcTemplate.query(sql, mapper, (Object[]) new Object[] { ruleId, transactionType });// NOSONAR - } - - private static final class GLAccountDataLookUpMapper implements RowMapper { - - private static final String LOOKUP_SCHEMA = " gl.id as id, gl.name as name, gl.gl_code as glCode from acc_accounting_rule rule join acc_rule_tags tags on tags.acc_rule_id = rule.id join acc_gl_account gl on gl.tag_id=tags.tag_id"; - - @Override - public GLAccountDataForLookup mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { - final Long id = JdbcSupport.getLong(rs, "id"); - final String name = rs.getString("name"); - final String glCode = rs.getString("glCode"); - - return new GLAccountDataForLookup().setId(id).setName(name).setGlCode(glCode); - } - } -} +/** + * 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. + */ +package org.apache.fineract.accounting.glaccount.service; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.apache.fineract.accounting.common.AccountingEnumerations; +import org.apache.fineract.accounting.glaccount.data.GLAccountData; +import org.apache.fineract.accounting.glaccount.data.GLAccountDataForLookup; +import org.apache.fineract.accounting.glaccount.domain.GLAccountType; +import org.apache.fineract.accounting.glaccount.domain.GLAccountUsage; +import org.apache.fineract.accounting.glaccount.exception.GLAccountInvalidClassificationException; +import org.apache.fineract.accounting.glaccount.exception.GLAccountNotFoundException; +import org.apache.fineract.accounting.journalentry.data.JournalEntryAssociationParametersData; +import org.apache.fineract.infrastructure.codes.data.CodeValueData; +import org.apache.fineract.infrastructure.core.data.EnumOptionData; +import org.apache.fineract.infrastructure.core.domain.JdbcSupport; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class GLAccountReadPlatformServiceImpl implements GLAccountReadPlatformService { + + private static final String NAME_DECORATED_BASE_ON_HIERARCHY = "concat(substring('........................................', 1, ((LENGTH(hierarchy) - LENGTH(REPLACE(hierarchy, '.', '')) - 1) * 4)), name)"; + + private final JdbcTemplate jdbcTemplate; + + private static final String SQL_AND = " and "; + + private static final class GLAccountMapper implements RowMapper { + + private final JournalEntryAssociationParametersData associationParametersData; + + GLAccountMapper(final JournalEntryAssociationParametersData associationParametersData) { + if (associationParametersData == null) { + this.associationParametersData = new JournalEntryAssociationParametersData(); + } else { + this.associationParametersData = associationParametersData; + } + } + + public String schema() { + StringBuilder sb = new StringBuilder(); + sb.append( + " gl.id as id, name as name, parent_id as parentId, gl_code as glCode, disabled as disabled, manual_journal_entries_allowed as manualEntriesAllowed, ") + .append("classification_enum as classification, account_usage as accountUsage, gl.description as description, ") + .append(NAME_DECORATED_BASE_ON_HIERARCHY).append(" as nameDecorated, ") + .append("cv.id as codeId, cv.code_value as codeValue "); + if (this.associationParametersData.isRunningBalanceRequired()) { + sb.append(",gl_j.organization_running_balance as organizationRunningBalance "); + } + sb.append("from acc_gl_account gl left join m_code_value cv on tag_id=cv.id "); + if (this.associationParametersData.isRunningBalanceRequired()) { + sb.append("left outer join acc_gl_journal_entry gl_j on gl_j.id = (") + .append("select id from acc_gl_journal_entry ") + .append("where account_id = gl.id ") + .append("order by id desc limit 1) "); + } + return sb.toString(); + } + + @Override + public GLAccountData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + + final Long id = rs.getLong("id"); + final String name = rs.getString("name"); + final Long parentId = JdbcSupport.getLong(rs, "parentId"); + final String glCode = rs.getString("glCode"); + final boolean disabled = rs.getBoolean("disabled"); + final boolean manualEntriesAllowed = rs.getBoolean("manualEntriesAllowed"); + final int accountTypeId = JdbcSupport.getInteger(rs, "classification"); + final EnumOptionData accountType = AccountingEnumerations.gLAccountType(accountTypeId); + final int usageId = JdbcSupport.getInteger(rs, "accountUsage"); + final EnumOptionData usage = AccountingEnumerations.gLAccountUsage(usageId); + final String description = rs.getString("description"); + final String nameDecorated = rs.getString("nameDecorated"); + final Long codeId = rs.wasNull() ? null : rs.getLong("codeId"); + final String codeValue = rs.getString("codeValue"); + final CodeValueData tagId = CodeValueData.instance(codeId, codeValue); + Long organizationRunningBalance = null; + if (associationParametersData.isRunningBalanceRequired()) { + organizationRunningBalance = rs.getLong("organizationRunningBalance"); + } + return new GLAccountData().setId(id).setName(name).setParentId(parentId).setGlCode(glCode).setDisabled(disabled) + .setManualEntriesAllowed(manualEntriesAllowed).setType(accountType).setUsage(usage).setDescription(description) + .setNameDecorated(nameDecorated).setTagId(tagId).setOrganizationRunningBalance(organizationRunningBalance); + } + } + + @Override + public List retrieveAllGLAccounts(final Integer accountClassification, final String searchParam, final Integer usage, + final Boolean manualTransactionsAllowed, final Boolean disabled, + JournalEntryAssociationParametersData associationParametersData) { + if (accountClassification != null && !checkValidGLAccountType(accountClassification)) { + throw new GLAccountInvalidClassificationException(accountClassification); + } + + if (usage != null && !checkValidGLAccountUsage(usage)) { + throw new GLAccountInvalidClassificationException(accountClassification); + } + + final GLAccountMapper rm = new GLAccountMapper(associationParametersData); + String sql = "select " + rm.schema(); + // append SQL statement for fetching account totals + if (associationParametersData != null && associationParametersData.isRunningBalanceRequired()) { + sql = sql + " and gl_j.id in (select t1.id from (select t2.account_id, max(t2.id) as id from " + + "(select id, max(entry_date) as entry_date, account_id from acc_gl_journal_entry where is_running_balance_calculated = true " + + "group by account_id desc, id) t3 inner join acc_gl_journal_entry t2 on t2.account_id = t3.account_id and t2.entry_date = t3.entry_date " + + "group by t2.account_id desc) t1)"; + } + final Object[] parameterArray = new Object[3]; + int arrayPos = 0; + boolean filtersPresent = false; + if ((accountClassification != null) || StringUtils.isNotBlank(searchParam) || (usage != null) || (manualTransactionsAllowed != null) + || (disabled != null)) { + filtersPresent = true; + sql += " where"; + } + + if (filtersPresent) { + boolean firstWhereConditionAdded = false; + if (accountClassification != null) { + sql += " classification_enum = ?"; + parameterArray[arrayPos] = accountClassification.shortValue(); + arrayPos = arrayPos + 1; + firstWhereConditionAdded = true; + } + if (StringUtils.isNotBlank(searchParam)) { + if (firstWhereConditionAdded) { + sql += SQL_AND; + } + sql += " ( name like ? or gl_code like ? )"; + parameterArray[arrayPos] = "%" + searchParam + "%"; + arrayPos = arrayPos + 1; + parameterArray[arrayPos] = "%" + searchParam + "%"; + arrayPos = arrayPos + 1; + firstWhereConditionAdded = true; + } + if (usage != null) { + if (firstWhereConditionAdded) { + sql += SQL_AND; + } + if (GLAccountUsage.HEADER.getValue().equals(usage)) { + sql += " account_usage = 2 "; + } else if (GLAccountUsage.DETAIL.getValue().equals(usage)) { + sql += " account_usage = 1 "; + } + firstWhereConditionAdded = true; + } + if (manualTransactionsAllowed != null) { + if (firstWhereConditionAdded) { + sql += SQL_AND; + } + + sql += " manual_journal_entries_allowed = " + manualTransactionsAllowed; + firstWhereConditionAdded = true; + } + if (disabled != null) { + if (firstWhereConditionAdded) { + sql += SQL_AND; + } + + sql += " disabled = " + disabled; + } + } + + sql += " ORDER BY gl_code ASC"; + + final Object[] finalObjectArray = Arrays.copyOf(parameterArray, arrayPos); + return this.jdbcTemplate.query(sql, rm, (Object[]) finalObjectArray);// NOSONAR + } + + @Override + public GLAccountData retrieveGLAccountById(final long glAccountId, JournalEntryAssociationParametersData associationParametersData) { + try { + final GLAccountMapper rm = new GLAccountMapper(associationParametersData); + final StringBuilder sql = new StringBuilder(); + sql.append("select ").append(rm.schema()); + sql.append(" where gl.id = ?"); + if (associationParametersData.isRunningBalanceRequired()) { + sql.append(" and gl_j.is_running_balance_calculated = true ") + .append(" ORDER BY gl_j.entry_date DESC,gl_j.id DESC LIMIT 1"); + } + + return this.jdbcTemplate.queryForObject(sql.toString(), rm, new Object[] { glAccountId }); + } catch (final EmptyResultDataAccessException e) { + throw new GLAccountNotFoundException(glAccountId, e); + } + } + + @Override + public List retrieveAllEnabledDetailGLAccounts(final GLAccountType accountType) { + return retrieveAllGLAccounts(accountType.getValue(), null, GLAccountUsage.DETAIL.getValue(), null, false, + new JournalEntryAssociationParametersData()); + } + + @Override + public List retrieveAllEnabledDetailGLAccounts() { + return retrieveAllGLAccounts(null, null, GLAccountUsage.DETAIL.getValue(), null, false, + new JournalEntryAssociationParametersData()); + } + + private static boolean checkValidGLAccountType(final int type) { + for (final GLAccountType accountType : GLAccountType.values()) { + if (accountType.getValue().equals(type)) { + return true; + } + } + return false; + } + + private static boolean checkValidGLAccountUsage(final int type) { + for (final GLAccountUsage accountUsage : GLAccountUsage.values()) { + if (accountUsage.getValue().equals(type)) { + return true; + } + } + return false; + } + + @Override + public GLAccountData retrieveNewGLAccountDetails(final Integer type) { + return GLAccountData.sensibleDefaultsForNewGLAccountCreation(type); + } + + @Override + public List retrieveAllEnabledHeaderGLAccounts(final GLAccountType accountType) { + return retrieveAllGLAccounts(accountType.getValue(), null, GLAccountUsage.HEADER.getValue(), null, false, + new JournalEntryAssociationParametersData()); + } + + @Override + public List retrieveAccountsByTagId(final Long ruleId, final Integer transactionType) { + final GLAccountDataLookUpMapper mapper = new GLAccountDataLookUpMapper(); + final String sql = "Select " + GLAccountDataLookUpMapper.LOOKUP_SCHEMA + " where rule.id=? and tags.acc_type_enum=?"; + return this.jdbcTemplate.query(sql, mapper, (Object[]) new Object[] { ruleId, transactionType });// NOSONAR + } + + private static final class GLAccountDataLookUpMapper implements RowMapper { + + private static final String LOOKUP_SCHEMA = " gl.id as id, gl.name as name, gl.gl_code as glCode from acc_accounting_rule rule join acc_rule_tags tags on tags.acc_rule_id = rule.id join acc_gl_account gl on gl.tag_id=tags.tag_id"; + + @Override + public GLAccountDataForLookup mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + final Long id = JdbcSupport.getLong(rs, "id"); + final String name = rs.getString("name"); + final String glCode = rs.getString("glCode"); + + return new GLAccountDataForLookup().setId(id).setName(name).setGlCode(glCode); + } + } +} 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 30b1fa477..ef18922dd 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 @@ -344,4 +344,5 @@ + diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0317_grant_cashier_gl_loan_share_read_permissions.xml b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0317_grant_cashier_gl_loan_share_read_permissions.xml new file mode 100644 index 000000000..846eff429 --- /dev/null +++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0317_grant_cashier_gl_loan_share_read_permissions.xml @@ -0,0 +1,49 @@ + + + + + + + + INSERT INTO m_role_permission (role_id, permission_id) + SELECT r.id, p.id + FROM m_role r + JOIN m_permission p ON p.code IN ( + 'READ_GLACCOUNT', + 'READ_LOAN', + 'READ_SHAREACCOUNT' + ) + WHERE r.name = 'CASHIER' + AND NOT EXISTS ( + SELECT 1 FROM m_role_permission rp + WHERE rp.role_id = r.id AND rp.permission_id = p.id + ); + + + DELETE FROM m_role_permission + WHERE role_id = (SELECT id FROM m_role WHERE name = 'CASHIER') + AND permission_id IN ( + SELECT id FROM m_permission + WHERE code IN ( + 'READ_GLACCOUNT', + 'READ_LOAN', + 'READ_SHAREACCOUNT' + ) + ); + + + +