diff --git a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/bulkimport/importhandler/client/ClientEntityImportHandlerTest.java b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/bulkimport/importhandler/client/ClientEntityImportHandlerTest.java index 95174e24e0c..ee5e734d196 100644 --- a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/bulkimport/importhandler/client/ClientEntityImportHandlerTest.java +++ b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/bulkimport/importhandler/client/ClientEntityImportHandlerTest.java @@ -115,10 +115,10 @@ public void testClientImport() throws InterruptedException, IOException, ParseEx firstClientRow.createCell(ClientEntityConstants.SUBMITTED_ON_COL).setCellValue(submittedDate); firstClientRow.createCell(ClientEntityConstants.ADDRESS_ENABLED).setCellValue("False"); - File directory=new File(System.getProperty("user.home")+"\\Fineract\\bulkimport\\integration_tests\\importhandler\\client") ; + File directory=new File(System.getProperty("user.home")+File.separator+"Fineract"+File.separator+"bulkimport"+File.separator+"integration_tests"+File.separator+"importhandler"+File.separator+"client") ; if (!directory.exists()) directory.mkdirs(); - File file= new File(directory+"\\ClientEntity.xls"); + File file= new File(directory+File.separator+"ClientEntity.xls"); OutputStream outputStream=new FileOutputStream(file); workbook.write(outputStream); outputStream.close(); diff --git a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/bulkimport/importhandler/loan/LoanImportHandlerTest.java b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/bulkimport/importhandler/loan/LoanImportHandlerTest.java index 66a35393022..91bb0bdb249 100644 --- a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/bulkimport/importhandler/loan/LoanImportHandlerTest.java +++ b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/bulkimport/importhandler/loan/LoanImportHandlerTest.java @@ -80,27 +80,28 @@ public void testLoanImport() throws InterruptedException, IOException, ParseExce Integer outcome_staff_creation =staffHelper.createStaff(requestSpec,responseSpec); Assert.assertNotNull("Could not create staff",outcome_staff_creation); - LoanTransactionHelper loanTransactionHelper=new LoanTransactionHelper(requestSpec,responseSpec); - LoanProductTestBuilder loanProductTestBuilder=new LoanProductTestBuilder(); - String jsonLoanProduct=loanProductTestBuilder.build(null); - Integer outcome_lp_creaion=loanTransactionHelper.getLoanProductId(jsonLoanProduct); - Assert.assertNotNull("Could not create Loan Product" ,outcome_lp_creaion); - - FundsResourceHandler fundsResourceHandler=new FundsResourceHandler(); - String jsonFund="{\n" + - "\t\"name\": \""+Utils.randomNameGenerator("Fund_Name",9)+"\"\n" + - "}"; - Integer outcome_fund_creation=fundsResourceHandler.createFund(jsonFund,requestSpec,responseSpec); - Assert.assertNotNull("Could not create Fund" ,outcome_fund_creation); - - PaymentTypeHelper paymentTypeHelper=new PaymentTypeHelper(); - String name = PaymentTypeHelper.randomNameGenerator("P_T", 5); - String description = PaymentTypeHelper.randomNameGenerator("PT_Desc", 15); - Boolean isCashPayment = true; - Integer position = 1; - Integer outcome_payment_creation= paymentTypeHelper.createPaymentType(requestSpec, responseSpec,name,description,isCashPayment,position); - Assert.assertNotNull("Could not create payment type" ,outcome_payment_creation); + // LoanTransactionHelper ltHelper=new LoanTransactionHelper(requestSpec,responseSpec); + // LoanProductTestBuilder loanProductTestBuilder=new LoanProductTestBuilder(); + // String jsonLoanProduct=loanProductTestBuilder.build(null); + // Integer outcome_lp_creaion=ltHelper.getLoanProductId(jsonLoanProduct); + // Assert.assertNotNull("Could not create Loan Product" ,outcome_lp_creaion); + + // FundsResourceHandler fundsResourceHandler=new FundsResourceHandler(); + // String jsonFund="{\n" + + // "\t\"name\": \""+Utils.randomNameGenerator("Fund_Name",9)+"\"\n" + + // "}"; + // Integer outcome_fund_creation=fundsResourceHandler.createFund(jsonFund,requestSpec,responseSpec); + // Assert.assertNotNull("Could not create Fund" ,outcome_fund_creation); + + // PaymentTypeHelper paymentTypeHelper=new PaymentTypeHelper(); + // String name = PaymentTypeHelper.randomNameGenerator("P_T", 5); + // String description = PaymentTypeHelper.randomNameGenerator("PT_Desc", 15); + // Boolean isCashPayment = true; + // Integer position = 1; + // Integer outcome_payment_creation= paymentTypeHelper.createPaymentType(requestSpec, responseSpec,name,description,isCashPayment,position); + // Assert.assertNotNull("Could not create payment type" ,outcome_payment_creation); + LoanTransactionHelper loanTransactionHelper=new LoanTransactionHelper(requestSpec,responseSpec); Workbook workbook=loanTransactionHelper.getLoanWorkbook("dd MMMM yyyy"); //insert dummy data into loan Sheet @@ -127,7 +128,7 @@ public void testLoanImport() throws InterruptedException, IOException, ParseExce firstLoanRow.createCell(LoanConstants.NO_OF_REPAYMENTS_COL).setCellValue(loanProductSheet.getRow(1).getCell(6).getNumericCellValue()); firstLoanRow.createCell(LoanConstants.REPAID_EVERY_COL).setCellValue(loanProductSheet.getRow(1).getCell(9).getNumericCellValue()); firstLoanRow.createCell(LoanConstants.REPAID_EVERY_FREQUENCY_COL).setCellValue(loanProductSheet.getRow(1).getCell(10).getStringCellValue()); - firstLoanRow.createCell(LoanConstants.LOAN_TERM_COL).setCellValue(loanProductSheet.getRow(1).getCell(8).getNumericCellValue()); + firstLoanRow.createCell(LoanConstants.LOAN_TERM_COL).setCellValue(60); firstLoanRow.createCell(LoanConstants.LOAN_TERM_FREQUENCY_COL).setCellValue(loanProductSheet.getRow(1).getCell(10).getStringCellValue()); firstLoanRow.createCell(LoanConstants.NOMINAL_INTEREST_RATE_COL).setCellValue(loanProductSheet.getRow(1).getCell(11).getNumericCellValue()); firstLoanRow.createCell(LoanConstants.NOMINAL_INTEREST_RATE_FREQUENCY_COL).setCellValue(loanProductSheet.getRow(1).getCell(14).getStringCellValue()); @@ -144,10 +145,12 @@ public void testLoanImport() throws InterruptedException, IOException, ParseExce firstLoanRow.createCell(LoanConstants.LAST_REPAYMENT_DATE_COL).setCellValue(date); firstLoanRow.createCell(LoanConstants.REPAYMENT_TYPE_COL).setCellValue(extrasSheet.getRow(1).getCell(3).getStringCellValue()); - File directory=new File(System.getProperty("user.home")+"\\Fineract\\bulkimport\\integration_tests\\importhandler\\loan") ; + String currentdirectory = new File("").getAbsolutePath(); + File directory=new File(currentdirectory+File.separator+"src"+File.separator+"integrationTest"+File.separator+ + "resources"+File.separator+"bulkimport"+File.separator+"importhandler"+File.separator+"loan") ; if (!directory.exists()) directory.mkdirs(); - File file= new File(directory+"\\Loan.xls"); + File file= new File(directory+File.separator+"Loan.xls"); OutputStream outputStream=new FileOutputStream(file); workbook.write(outputStream); outputStream.close(); @@ -157,7 +160,7 @@ public void testLoanImport() throws InterruptedException, IOException, ParseExce Assert.assertNotNull(importDocumentId); //Wait for the creation of output excel - Thread.sleep(3000); + Thread.sleep(10000); //check status column of output excel String location=loanTransactionHelper.getOutputTemplateLocation(importDocumentId); diff --git a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/bulkimport/importhandler/office/OfficeImportHandlerTest.java b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/bulkimport/importhandler/office/OfficeImportHandlerTest.java index e4dd0aa8397..9bd80bc8ef9 100644 --- a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/bulkimport/importhandler/office/OfficeImportHandlerTest.java +++ b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/bulkimport/importhandler/office/OfficeImportHandlerTest.java @@ -74,11 +74,11 @@ public void testOfficeImport() throws IOException, InterruptedException, NoSuchF firstOfficeRow.createCell(OfficeConstants.OPENED_ON_COL).setCellValue(date); String currentdirectory = new File("").getAbsolutePath(); - File directory=new File(currentdirectory+"\\src\\integrationTest\\" + - "resources\\bulkimport\\importhandler\\office"); + File directory=new File(currentdirectory+File.separator+"src"+File.separator+"integrationTest"+File.separator+ + "resources"+File.separator+"bulkimport"+File.separator+"importhandler"+File.separator+"office"); if (!directory.exists()) directory.mkdirs(); - File file= new File(directory+"\\Office.xls"); + File file= new File(directory+File.separator+"Office.xls"); OutputStream outputStream=new FileOutputStream(file); workbook.write(outputStream); outputStream.close(); diff --git a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/bulkimport/importhandler/savings/SavingsImportHandlerTest.java b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/bulkimport/importhandler/savings/SavingsImportHandlerTest.java index 50d7d571c43..c22ec1f2002 100644 --- a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/bulkimport/importhandler/savings/SavingsImportHandlerTest.java +++ b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/bulkimport/importhandler/savings/SavingsImportHandlerTest.java @@ -118,17 +118,19 @@ public void testSavingsImport() throws InterruptedException, IOException, ParseE firstSavingsRow.createCell(SavingsConstants.INTEREST_POSTING_PERIOD_COL).setCellValue(savingsProductSheet.getRow(1).getCell(4).getStringCellValue()); firstSavingsRow.createCell(SavingsConstants.INTEREST_CALCULATION_COL).setCellValue(savingsProductSheet.getRow(1).getCell(5).getStringCellValue()); firstSavingsRow.createCell(SavingsConstants.INTEREST_CALCULATION_DAYS_IN_YEAR_COL).setCellValue(savingsProductSheet.getRow(1).getCell(6).getStringCellValue()); - firstSavingsRow.createCell(SavingsConstants.MIN_OPENING_BALANCE_COL).setCellValue(savingsProductSheet.getRow(1).getCell(7).getNumericCellValue()); - firstSavingsRow.createCell(SavingsConstants.LOCKIN_PERIOD_COL).setCellValue(savingsProductSheet.getRow(1).getCell(8).getNumericCellValue()); - firstSavingsRow.createCell(SavingsConstants.LOCKIN_PERIOD_FREQUENCY_COL).setCellValue(savingsProductSheet.getRow(1).getCell(9).getStringCellValue()); + firstSavingsRow.createCell(SavingsConstants.MIN_OPENING_BALANCE_COL).setCellValue(1000.0); + firstSavingsRow.createCell(SavingsConstants.LOCKIN_PERIOD_COL).setCellValue(1); + firstSavingsRow.createCell(SavingsConstants.LOCKIN_PERIOD_FREQUENCY_COL).setCellValue("Weeks"); firstSavingsRow.createCell(SavingsConstants.APPLY_WITHDRAWAL_FEE_FOR_TRANSFERS).setCellValue("False"); firstSavingsRow.createCell(SavingsConstants.ALLOW_OVER_DRAFT_COL).setCellValue("False"); firstSavingsRow.createCell(SavingsConstants.OVER_DRAFT_LIMIT_COL).setCellValue(savingsProductSheet.getRow(1).getCell(15).getNumericCellValue()); - File directory=new File(System.getProperty("user.home")+"\\Fineract\\bulkimport\\integration_tests\\importhandler\\savings") ; + String currentdirectory = new File("").getAbsolutePath(); + File directory=new File(currentdirectory+File.separator+"src"+File.separator+"integrationTest"+File.separator+ + "resources"+File.separator+"bulkimport"+File.separator+"importhandler"+File.separator+"savings") ; if (!directory.exists()) directory.mkdirs(); - File file= new File(directory+"\\Savings.xls"); + File file= new File(directory+File.separator+"Savings.xls"); OutputStream outputStream=new FileOutputStream(file); workbook.write(outputStream); outputStream.close(); @@ -138,7 +140,7 @@ public void testSavingsImport() throws InterruptedException, IOException, ParseE Assert.assertNotNull(importDocumentId); //Wait for the creation of output excel - Thread.sleep(3000); + Thread.sleep(10000); //check status column of output excel String location=savingsAccountHelper.getOutputTemplateLocation(importDocumentId); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java index 31fdfca54ae..29ec818fbb8 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java @@ -1187,8 +1187,8 @@ public GenericResultsetData retrieveDataTableGenericResultSet(final String dataT sql = sql + "select * from `" + dataTableName + "` where id = " + id; } - this.columnValidator.validateSqlInjection(sql, order); - if (order != null) { + if (StringUtils.isNotBlank(order)) { + this.columnValidator.validateSqlInjection(sql, order); sql = sql + " order by " + order; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/accountdetails/data/AccountSummaryCollectionData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/accountdetails/data/AccountSummaryCollectionData.java index f4faacaa32a..80de9a5f1b2 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/accountdetails/data/AccountSummaryCollectionData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/accountdetails/data/AccountSummaryCollectionData.java @@ -29,27 +29,34 @@ public class AccountSummaryCollectionData { private final Collection loanAccounts; private final Collection savingsAccounts; private final Collection shareAccounts ; + private final Collection guarantorAccounts; private final Collection memberLoanAccounts; private final Collection memberSavingsAccounts; - + private final Collection memberGuarantorAccounts; + public AccountSummaryCollectionData(final Collection loanAccounts, - final Collection savingsAccounts, final Collection shareAccounts) { + final Collection savingsAccounts, final Collection shareAccounts, + final Collection guarantorAccounts) { this.loanAccounts = defaultLoanAccountsIfEmpty(loanAccounts); this.savingsAccounts = defaultSavingsAccountsIfEmpty(savingsAccounts); this.shareAccounts = defaultShareAccountsIfEmpty(shareAccounts) ; + this.guarantorAccounts = guarantorAccounts; this.memberLoanAccounts = null; this.memberSavingsAccounts = null; + this.memberGuarantorAccounts = null; } public AccountSummaryCollectionData(final Collection loanAccounts, - final Collection savingsAccounts, final Collection memberLoanAccounts, - final Collection memberSavingsAccounts) { + final Collection savingsAccounts, final Collection guarantorAccounts, final Collection memberLoanAccounts, + final Collection memberSavingsAccounts, final Collection memberGuarantorAccounts) { this.loanAccounts = defaultLoanAccountsIfEmpty(loanAccounts); this.savingsAccounts = defaultSavingsAccountsIfEmpty(savingsAccounts); + this.guarantorAccounts = guarantorAccounts; this.shareAccounts = null ; this.memberLoanAccounts = defaultLoanAccountsIfEmpty(memberLoanAccounts); this.memberSavingsAccounts = defaultSavingsAccountsIfEmpty(memberSavingsAccounts); + this.memberGuarantorAccounts = defaultGuarantorAccountsIfEmpty(memberGuarantorAccounts); } private Collection defaultLoanAccountsIfEmpty(final Collection collection) { @@ -76,4 +83,11 @@ private Collection defaultShareAccountsIfEmpty(final Co return returnCollection; } + private Collection defaultGuarantorAccountsIfEmpty(final Collection collection) { + Collection returnCollection = null; + if (collection != null && !collection.isEmpty()) { + returnCollection = collection; + } + return returnCollection; + } } \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/accountdetails/data/GuarantorAccountSummaryData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/accountdetails/data/GuarantorAccountSummaryData.java new file mode 100644 index 00000000000..64f444e82d9 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/accountdetails/data/GuarantorAccountSummaryData.java @@ -0,0 +1,70 @@ +/** + * 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.portfolio.accountdetails.data; + +import java.math.BigDecimal; + +import org.apache.fineract.infrastructure.core.data.EnumOptionData; +import org.apache.fineract.portfolio.loanaccount.data.LoanApplicationTimelineData; +import org.apache.fineract.portfolio.loanaccount.data.LoanStatusEnumData; + +/** + * Immutable data object for loan accounts. + */ +@SuppressWarnings("unused") +public class GuarantorAccountSummaryData { + + private final Long id; + private final String accountNo; + private final String externalId; + private final Long productId; + private final String productName; + private final String shortProductName; + private final LoanStatusEnumData status; + private final EnumOptionData loanType; + private final Integer loanCycle; + private final Boolean inArrears; + private final BigDecimal originalLoan; + private final BigDecimal loanBalance; + private final BigDecimal amountPaid; + private final Boolean isActive; + private final String relationship; + private final BigDecimal onHoldAmount; + public GuarantorAccountSummaryData(final Long id, final String accountNo, final String externalId, final Long productId, + final String loanProductName, final String shortLoanProductName, final LoanStatusEnumData loanStatus, final EnumOptionData loanType, final Integer loanCycle, + final Boolean inArrears,final BigDecimal originalLoan,final BigDecimal loanBalance,final BigDecimal amountPaid, + final Boolean isActive, final String relationship, final BigDecimal onHoldAmount) { + this.id = id; + this.accountNo = accountNo; + this.externalId = externalId; + this.productId = productId; + this.productName = loanProductName; + this.shortProductName = shortLoanProductName; + this.status = loanStatus; + this.loanType = loanType; + this.loanCycle = loanCycle; + this.inArrears = inArrears; + this.loanBalance = loanBalance; + this.originalLoan = originalLoan; + this.amountPaid = amountPaid; + this.isActive = isActive; + this.relationship = relationship; + this.onHoldAmount = onHoldAmount; + } +} \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/accountdetails/service/AccountDetailsReadPlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/accountdetails/service/AccountDetailsReadPlatformServiceJpaRepositoryImpl.java index 0fc91036b5c..b4b1bb7e585 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/accountdetails/service/AccountDetailsReadPlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/accountdetails/service/AccountDetailsReadPlatformServiceJpaRepositoryImpl.java @@ -30,6 +30,7 @@ import org.apache.fineract.infrastructure.security.utils.ColumnValidator; import org.apache.fineract.organisation.monetary.data.CurrencyData; import org.apache.fineract.portfolio.accountdetails.data.AccountSummaryCollectionData; +import org.apache.fineract.portfolio.accountdetails.data.GuarantorAccountSummaryData; import org.apache.fineract.portfolio.accountdetails.data.LoanAccountSummaryData; import org.apache.fineract.portfolio.accountdetails.data.SavingsAccountSummaryData; import org.apache.fineract.portfolio.accountdetails.data.ShareAccountSummaryData; @@ -75,10 +76,14 @@ public AccountSummaryCollectionData retrieveClientAccountDetails(final Long clie this.clientReadPlatformService.retrieveOne(clientId); final String loanwhereClause = " where l.client_id = ?"; final String savingswhereClause = " where sa.client_id = ? order by sa.status_enum ASC, sa.account_no ASC"; + final String guarantorWhereClause = " where g.entity_id = ? and g.is_active = 1 order by l.account_no ASC"; + final List loanAccounts = retrieveLoanAccountDetails(loanwhereClause, new Object[] { clientId }); final List savingsAccounts = retrieveAccountDetails(savingswhereClause, new Object[] { clientId }); final List shareAccounts = retrieveShareAccountDetails(clientId) ; - return new AccountSummaryCollectionData(loanAccounts, savingsAccounts, shareAccounts); + final List guarantorloanAccounts = retrieveGuarantorLoanAccountDetails( + guarantorWhereClause, new Object[] { clientId }); + return new AccountSummaryCollectionData(loanAccounts, savingsAccounts, shareAccounts, guarantorloanAccounts); } @Override @@ -89,14 +94,21 @@ public AccountSummaryCollectionData retrieveGroupAccountDetails(final Long group final String loanWhereClauseForMembers = " where l.group_id = ? and l.client_id is not null"; final String savingswhereClauseForGroup = " where sa.group_id = ? and sa.client_id is null order by sa.status_enum ASC, sa.account_no ASC"; final String savingswhereClauseForMembers = " where sa.group_id = ? and sa.client_id is not null order by sa.status_enum ASC, sa.account_no ASC"; + final String guarantorWhereClauseForGroup = " where l.group_id = ? and l.client_id is null and g.is_active = 1 order by l.account_no ASC"; + final String guarantorWhereClauseForMembers = " where l.group_id = ? and l.client_id is not null and g.is_active = 1 order by l.account_no ASC"; + final List groupLoanAccounts = retrieveLoanAccountDetails(loanWhereClauseForGroup, new Object[] { groupId }); final List groupSavingsAccounts = retrieveAccountDetails(savingswhereClauseForGroup, new Object[] { groupId }); + final List groupGuarantorloanAccounts = retrieveGuarantorLoanAccountDetails( + guarantorWhereClauseForGroup, new Object[] { groupId }); final List memberLoanAccounts = retrieveLoanAccountDetails(loanWhereClauseForMembers, new Object[] { groupId }); final List memberSavingsAccounts = retrieveAccountDetails(savingswhereClauseForMembers, new Object[] { groupId }); - return new AccountSummaryCollectionData(groupLoanAccounts, groupSavingsAccounts, memberLoanAccounts, memberSavingsAccounts); + final List memberGuarantorloanAccounts = retrieveGuarantorLoanAccountDetails( + guarantorWhereClauseForMembers, new Object[] { groupId }); + return new AccountSummaryCollectionData(groupLoanAccounts, groupSavingsAccounts, groupGuarantorloanAccounts, memberLoanAccounts, memberSavingsAccounts, memberGuarantorloanAccounts); } @Override @@ -144,6 +156,14 @@ private List retrieveShareAccountDetails(final Long cli return this.jdbcTemplate.query(query, mapper, new Object [] {clientId}); } + private List retrieveGuarantorLoanAccountDetails( + final String loanwhereClause, final Object[] inputs) { + final GuarantorLoanAccountSummaryDataMapper rm = new GuarantorLoanAccountSummaryDataMapper(); + final String sql = "select " + rm.guarantorLoanAccountSummarySchema() + + loanwhereClause; + return this.jdbcTemplate.query(sql, rm, inputs); + } + private final static class ShareAccountSummaryDataMapper implements RowMapper { private final String schema ; @@ -493,6 +513,97 @@ public LoanAccountSummaryData mapRow(final ResultSet rs, @SuppressWarnings("unus return new LoanAccountSummaryData(id, accountNo, externalId, productId, loanProductName, shortLoanProductName, loanStatus, loanType, loanCycle, timeline, inArrears,originalLoan,loanBalance,amountPaid); } + + } + private static final class GuarantorLoanAccountSummaryDataMapper implements + RowMapper { + + public String guarantorLoanAccountSummarySchema() { + + final StringBuilder accountsSummary = new StringBuilder( + "l.id as id, l.account_no as accountNo, l.external_id as externalId,"); + accountsSummary + .append(" l.product_id as productId, lp.name as productName, lp.short_name as shortProductName,") + .append(" l.loan_status_id as statusId, l.loan_type_enum as loanType,") + + .append("l.principal_disbursed_derived as originalLoan,") + .append("l.total_outstanding_derived as loanBalance,") + .append("l.total_repayment_derived as amountPaid,") + + .append(" l.loan_product_counter as loanCycle,") + + .append(" l.submittedon_date as submittedOnDate,") + + .append(" l.rejectedon_date as rejectedOnDate,") + .append(" l.withdrawnon_date as withdrawnOnDate,") + .append(" l.approvedon_date as approvedOnDate,") + .append(" l.expected_disbursedon_date as expectedDisbursementDate, l.disbursedon_date as actualDisbursementDate,") + .append(" l.closedon_date as closedOnDate,") + .append(" la.overdue_since_date_derived as overdueSinceDate,") + .append(" l.writtenoffon_date as writtenOffOnDate, l.expected_maturedon_date as expectedMaturityDate,") + .append(" g.is_active as isActive,") + .append(" cv.code_value as relationship,") + .append(" sa.on_hold_funds_derived") + .append(" from m_loan l ") + .append(" join m_guarantor as g on g.loan_id = l.id ") + .append(" join m_client as c on c.id = g.entity_id ") + .append(" LEFT JOIN m_product_loan AS lp ON lp.id = l.product_id") + .append(" left join m_loan_arrears_aging la on la.loan_id = l.id") + .append(" left join m_code_value cv ON cv.id = g.client_reln_cv_id") + .append(" left join m_savings_account sa on sa.client_id = c.id") + + ; + + return accountsSummary.toString(); + } + + @Override + public GuarantorAccountSummaryData mapRow(final ResultSet rs, + @SuppressWarnings("unused") final int rowNum) + throws SQLException { + + final Long id = JdbcSupport.getLong(rs, "id"); + final String accountNo = rs.getString("accountNo"); + final String externalId = rs.getString("externalId"); + final Long productId = JdbcSupport.getLong(rs, "productId"); + final String loanProductName = rs.getString("productName"); + final String shortLoanProductName = rs + .getString("shortProductName"); + final Integer loanStatusId = JdbcSupport.getInteger(rs, "statusId"); + final LoanStatusEnumData loanStatus = LoanEnumerations + .status(loanStatusId); + final Integer loanTypeId = JdbcSupport.getInteger(rs, "loanType"); + final EnumOptionData loanType = AccountEnumerations + .loanType(loanTypeId); + final Integer loanCycle = JdbcSupport.getInteger(rs, "loanCycle"); + + final BigDecimal originalLoan = JdbcSupport + .getBigDecimalDefaultToNullIfZero(rs, "originalLoan"); + final BigDecimal loanBalance = JdbcSupport + .getBigDecimalDefaultToNullIfZero(rs, "loanBalance"); + final BigDecimal amountPaid = JdbcSupport + .getBigDecimalDefaultToNullIfZero(rs, "amountPaid"); + final BigDecimal onHoldAmount = JdbcSupport + .getBigDecimalDefaultToNullIfZero(rs, + "on_hold_funds_derived"); + + final LocalDate overdueSinceDate = JdbcSupport.getLocalDate(rs, + "overdueSinceDate"); + Boolean inArrears = true; + if (overdueSinceDate == null) { + inArrears = false; + } + + final Boolean isActive = rs.getBoolean("isActive"); + + final String relationship = rs.getString("relationship"); + return new GuarantorAccountSummaryData(id, accountNo, externalId, + productId, loanProductName, shortLoanProductName, + loanStatus, loanType, loanCycle, inArrears, originalLoan, + loanBalance, amountPaid, isActive, relationship, + onHoldAmount); + } + } -} +} \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/domain/Group.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/domain/Group.java index c3a14ae7dc7..a40aad7e8d1 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/domain/Group.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/domain/Group.java @@ -108,7 +108,7 @@ public final class Group extends AbstractPersistableCustom { @OneToMany(fetch = FetchType.EAGER) @JoinColumn(name = "parent_id") - private final List groupMembers = new LinkedList<>(); + private List groupMembers = new LinkedList<>(); @ManyToMany @JoinTable(name = "m_group_client", joinColumns = @JoinColumn(name = "group_id"), inverseJoinColumns = @JoinColumn(name = "client_id")) @@ -744,4 +744,10 @@ public void updateAccountNo(final String accountIdentifier) { this.accountNumber = accountIdentifier; this.accountNumberRequiresAutoGeneration = false; } + + public void setGroupMembers(List groupMembers) { + this.groupMembers = groupMembers; + } + + } \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/CalculateLoanScheduleQueryFromApiJsonHelper.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/CalculateLoanScheduleQueryFromApiJsonHelper.java index d33ea1df1bb..3a8fe380090 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/CalculateLoanScheduleQueryFromApiJsonHelper.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/CalculateLoanScheduleQueryFromApiJsonHelper.java @@ -148,6 +148,16 @@ public void validateSelectedPeriodFrequencyTypeIsTheSame(final List suggestsedLoanTerm) { + final ApiParameterError error = ApiParameterError + .parameterError( + "validation.msg.loan.loanTermFrequency.greater.than.repayment.structure.suggests", + "The parameter loanTermFrequency is greater than the suggested loan term as indicated by numberOfRepayments and repaymentEvery.", + "loanTermFrequency", loanTermFrequency, numberOfRepayments, repaymentEvery); + dataValidationErrors.add(error); + } + } } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java index f5a78c2da4e..45169df1ba3 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java @@ -88,7 +88,9 @@ import org.apache.fineract.portfolio.loanaccount.serialization.LoanApplicationCommandFromApiJsonHelper; import org.apache.fineract.portfolio.loanaccount.serialization.LoanApplicationTransitionApiJsonValidator; import org.apache.fineract.portfolio.loanproduct.LoanProductConstants; +import org.apache.fineract.portfolio.loanproduct.data.LoanProductData; import org.apache.fineract.portfolio.loanproduct.domain.*; +import org.apache.fineract.portfolio.loanproduct.service.LoanProductReadPlatformService; import org.apache.fineract.portfolio.loanproduct.exception.LinkedAccountRequiredException; import org.apache.fineract.portfolio.loanproduct.exception.LoanProductNotFoundException; import org.apache.fineract.portfolio.loanproduct.serialization.LoanProductDataValidator; @@ -104,6 +106,7 @@ import org.springframework.dao.DataIntegrityViolationException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; import com.google.gson.JsonArray; import com.google.gson.JsonElement; @@ -147,6 +150,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa private final GlobalConfigurationRepositoryWrapper globalConfigurationRepository; private final FineractEntityToEntityMappingRepository repository; private final FineractEntityRelationRepository fineractEntityRelationRepository; + private final LoanProductReadPlatformService loanProductReadPlatformService; @Autowired public LoanApplicationWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final FromJsonHelper fromJsonHelper, @@ -169,7 +173,7 @@ public LoanApplicationWritePlatformServiceJpaRepositoryImpl(final PlatformSecuri final LoanScheduleAssembler loanScheduleAssembler, final LoanUtilService loanUtilService, final CalendarReadPlatformService calendarReadPlatformService, final GlobalConfigurationRepositoryWrapper globalConfigurationRepository, final FineractEntityToEntityMappingRepository repository, final FineractEntityRelationRepository fineractEntityRelationRepository, - final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService) { + final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService, final LoanProductReadPlatformService loanProductReadPlatformService) { this.context = context; this.fromJsonHelper = fromJsonHelper; this.loanApplicationTransitionApiJsonValidator = loanApplicationTransitionApiJsonValidator; @@ -204,6 +208,8 @@ public LoanApplicationWritePlatformServiceJpaRepositoryImpl(final PlatformSecuri this.globalConfigurationRepository = globalConfigurationRepository; this.repository = repository; this.fineractEntityRelationRepository = fineractEntityRelationRepository; + this.loanProductReadPlatformService = loanProductReadPlatformService; + } private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() { @@ -256,6 +262,8 @@ public CommandProcessingResult submitApplication(final JsonCommand command) { final Loan newLoanApplication = this.loanAssembler.assembleFrom(command, currentUser); + checkForProductMixRestrictions(newLoanApplication); + validateSubmittedOnDate(newLoanApplication); final LoanProductRelatedDetail productRelatedDetail = newLoanApplication.repaymentScheduleDetail(); @@ -415,6 +423,33 @@ public CommandProcessingResult submitApplication(final JsonCommand command) { } } + +public void checkForProductMixRestrictions(final Loan loan) { + + final List activeLoansLoanProductIds; + final Long productId = loan.loanProduct().getId(); + + if (loan.isGroupLoan()) { + activeLoansLoanProductIds = this.loanRepositoryWrapper.findActiveLoansLoanProductIdsByGroup(loan.getGroupId(), + LoanStatus.ACTIVE.getValue()); + } else { + activeLoansLoanProductIds = this.loanRepositoryWrapper.findActiveLoansLoanProductIdsByClient(loan.getClientId(), + LoanStatus.ACTIVE.getValue()); + } + checkForProductMixRestrictions(activeLoansLoanProductIds, productId, loan.loanProduct().productName()); + } + + private void checkForProductMixRestrictions(final List activeLoansLoanProductIds, final Long productId, final String productName) { + + if (!CollectionUtils.isEmpty(activeLoansLoanProductIds)) { + final Collection restrictedPrdouctsList = this.loanProductReadPlatformService + .retrieveRestrictedProductsForMix(productId); + for (final LoanProductData restrictedProduct : restrictedPrdouctsList) { + if (activeLoansLoanProductIds.contains(restrictedProduct.getId())) { throw new GeneralPlatformDomainRuleException("error.msg.loan.applied.or.to.be.disbursed.can.not.co-exist.with.the.loan.already.active.to.this.client", "This loan could not be applied/disbursed as the loan and `" + restrictedProduct + "` are not allowed to co-exist"); } + } + } + } + private void updateProductRelatedDetails(LoanProductRelatedDetail productRelatedDetail, Loan loan) { final Boolean amortization = loan.loanProduct().getLoanProductConfigurableAttributes().getAmortizationBoolean(); final Boolean arrearsTolerance = loan.loanProduct().getLoanProductConfigurableAttributes().getArrearsToleranceBoolean(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java index 99af8cde69b..b6eed1918a2 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java @@ -102,11 +102,9 @@ import org.apache.fineract.portfolio.loanaccount.serialization.LoanEventApiJsonValidator; import org.apache.fineract.portfolio.loanaccount.serialization.LoanUpdateCommandFromApiJsonDeserializer; import org.apache.fineract.portfolio.loanproduct.data.LoanOverdueDTO; -import org.apache.fineract.portfolio.loanproduct.data.LoanProductData; import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct; import org.apache.fineract.portfolio.loanproduct.exception.InvalidCurrencyException; import org.apache.fineract.portfolio.loanproduct.exception.LinkedAccountRequiredException; -import org.apache.fineract.portfolio.loanproduct.service.LoanProductReadPlatformService; import org.apache.fineract.portfolio.note.domain.Note; import org.apache.fineract.portfolio.note.domain.NoteRepository; import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail; @@ -151,7 +149,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf private final HolidayRepositoryWrapper holidayRepository; private final ConfigurationDomainService configurationDomainService; private final WorkingDaysRepositoryWrapper workingDaysRepository; - private final LoanProductReadPlatformService loanProductReadPlatformService; private final AccountTransfersWritePlatformService accountTransfersWritePlatformService; private final AccountTransfersReadPlatformService accountTransfersReadPlatformService; private final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService; @@ -186,7 +183,6 @@ public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext c final CalendarInstanceRepository calendarInstanceRepository, final PaymentDetailWritePlatformService paymentDetailWritePlatformService, final HolidayRepositoryWrapper holidayRepository, final ConfigurationDomainService configurationDomainService, final WorkingDaysRepositoryWrapper workingDaysRepository, - final LoanProductReadPlatformService loanProductReadPlatformService, final AccountTransfersWritePlatformService accountTransfersWritePlatformService, final AccountTransfersReadPlatformService accountTransfersReadPlatformService, final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService, @@ -222,7 +218,6 @@ public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext c this.holidayRepository = holidayRepository; this.configurationDomainService = configurationDomainService; this.workingDaysRepository = workingDaysRepository; - this.loanProductReadPlatformService = loanProductReadPlatformService; this.accountTransfersWritePlatformService = accountTransfersWritePlatformService; this.accountTransfersReadPlatformService = accountTransfersReadPlatformService; this.accountAssociationsReadPlatformService = accountAssociationsReadPlatformService; @@ -276,8 +271,6 @@ public CommandProcessingResult disburseLoan(final Long loanId, final JsonCommand entityDatatableChecksWritePlatformService.runTheCheckForProduct(loanId, EntityTables.LOAN.getName(), StatusEnum.DISBURSE.getCode().longValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId()); - // check for product mix validations - checkForProductMixRestrictions(loan); LocalDate recalculateFrom = null; if(!loan.isMultiDisburmentLoan()){ @@ -2267,32 +2260,6 @@ public void applyHolidaysToLoans() { this.holidayRepository.save(holidays); } - private void checkForProductMixRestrictions(final Loan loan) { - - final List activeLoansLoanProductIds; - final Long productId = loan.loanProduct().getId(); - - if (loan.isGroupLoan()) { - activeLoansLoanProductIds = this.loanRepositoryWrapper.findActiveLoansLoanProductIdsByGroup(loan.getGroupId(), - LoanStatus.ACTIVE.getValue()); - } else { - activeLoansLoanProductIds = this.loanRepositoryWrapper.findActiveLoansLoanProductIdsByClient(loan.getClientId(), - LoanStatus.ACTIVE.getValue()); - } - checkForProductMixRestrictions(activeLoansLoanProductIds, productId, loan.loanProduct().productName()); - } - - private void checkForProductMixRestrictions(final List activeLoansLoanProductIds, final Long productId, final String productName) { - - if (!CollectionUtils.isEmpty(activeLoansLoanProductIds)) { - final Collection restrictedPrdouctsList = this.loanProductReadPlatformService - .retrieveRestrictedProductsForMix(productId); - for (final LoanProductData restrictedProduct : restrictedPrdouctsList) { - if (activeLoansLoanProductIds.contains(restrictedProduct.getId())) { throw new LoanDisbursalException(productName, - restrictedProduct.getName()); } - } - } - } private void checkClientOrGroupActive(final Loan loan) { final Client client = loan.client();