diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm index d3354b26b..3236748e2 100644 --- a/api-docs/apiLive.htm +++ b/api-docs/apiLive.htm @@ -35848,8 +35848,8 @@ Request Body:

List Client Charges

-

The list capability of client charges can support pagination and sorting.

-
Mandatory Arguments
+

The list capability of client charges supports pagination.

+
Optional Arguments
offset
@@ -35867,7 +35867,7 @@ Request Body:
String optional
-
Only returns those charges which are pending payment (neither paid or waived).
+
Filters charges that are pending payment (neither paid or waived).

Example Requests:

clients/189/charges
diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanDisbursementDetailsIntegrationTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanDisbursementDetailsIntegrationTest.java index 169f289ec..32198f677 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanDisbursementDetailsIntegrationTest.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanDisbursementDetailsIntegrationTest.java @@ -7,6 +7,8 @@ package org.mifosplatform.integrationtests; import static org.junit.Assert.assertEquals; +import java.math.BigDecimal; +import java.math.MathContext; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -32,537 +34,454 @@ import com.jayway.restassured.specification.ResponseSpecification; @SuppressWarnings({ "rawtypes", "unchecked" }) public class LoanDisbursementDetailsIntegrationTest { - private ResponseSpecification responseSpec; - private RequestSpecification requestSpec; - private LoanTransactionHelper loanTransactionHelper; - private Integer loanID; - private Integer disbursementId; - final String approveDate = "01 March 2014"; - final String expectedDisbursementDate = "01 March 2014"; - final String proposedAmount = "5000"; - final String approvalAmount = "5000"; - - @Before - public void setup() { - Utils.initializeRESTAssured(); - this.requestSpec = new RequestSpecBuilder().setContentType( - ContentType.JSON).build(); - this.requestSpec - .header("Authorization", - "Basic " - + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); - this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200) - .build(); - this.loanTransactionHelper = new LoanTransactionHelper( - this.requestSpec, this.responseSpec); - } - - @Test - public void createAndValidateMultiDisburseLoansBasedOnEmi() { - List createTranches = new ArrayList<>(); - String id = null; - String installmentAmount = "800"; - String withoutInstallmentAmount = ""; - String proposedAmount = "10000"; - createTranches.add(this.loanTransactionHelper.createTrancheDetail(id, - "01 June 2015", "5000")); - createTranches.add(this.loanTransactionHelper.createTrancheDetail(id, - "01 Sep 2015", "5000")); - - final Integer clientID = ClientHelper.createClient(this.requestSpec, - this.responseSpec, "01 January 2014"); - System.out - .println("---------------------------------CLIENT CREATED WITH ID---------------------------------------------------" - + clientID); - - final Integer loanProductID = this.loanTransactionHelper - .getLoanProductId(new LoanProductTestBuilder() - .withInterestTypeAsDecliningBalance() - .withMoratorium("", "") - .withAmortizationTypeAsEqualInstallments() - .withTranches(true).build(null)); - System.out - .println("----------------------------------LOAN PRODUCT CREATED WITH ID-------------------------------------------" - + loanProductID); - - final Integer loanIDWithEmi = applyForLoanApplicationWithEmiAmount( - clientID, loanProductID, proposedAmount, createTranches, - installmentAmount); - - System.out - .println("-----------------------------------LOAN CREATED WITH EMI LOANID-------------------------------------------------" - + loanIDWithEmi); - - HashMap repaymentScheduleWithEmi = (HashMap) this.loanTransactionHelper - .getLoanDetail(this.requestSpec, this.responseSpec, - loanIDWithEmi, "repaymentSchedule"); - - ArrayList periods = (ArrayList) repaymentScheduleWithEmi - .get("periods"); - assertEquals(periods.size(), 15); - - this.validateRepaymentScheduleWithEMI(periods); - - HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan( - this.requestSpec, this.responseSpec, loanIDWithEmi); - LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap); - - System.out - .println("-----------------------------------APPROVE LOAN-----------------------------------------------------------"); - loanStatusHashMap = this.loanTransactionHelper - .approveLoanWithApproveAmount("01 June 2015", "01 June 2015", - "10000", loanIDWithEmi, createTranches); - LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); - LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap); - System.out - .println("-----------------------------------MULTI DISBURSAL LOAN WITH EMI APPROVED SUCCESSFULLY---------------------------------------"); - - final Integer loanIDWithoutEmi = applyForLoanApplicationWithEmiAmount( - clientID, loanProductID, proposedAmount, createTranches, - withoutInstallmentAmount); - - HashMap repaymentScheduleWithoutEmi = (HashMap) this.loanTransactionHelper - .getLoanDetail(this.requestSpec, this.responseSpec, - loanIDWithoutEmi, "repaymentSchedule"); - - ArrayList periods1 = (ArrayList) repaymentScheduleWithEmi - .get("periods"); - assertEquals(periods1.size(), 15); - - System.out - .println("-----------------------------------LOAN CREATED WITHOUT EMI LOANID-------------------------------------------------" - + loanIDWithoutEmi); - - /* To be uncommented once issue MIFOSX-2006 is closed. */ - // this.validateRepaymentScheduleWithoutEMI(periods1); - - HashMap loanStatusMap = LoanStatusChecker.getStatusOfLoan( - this.requestSpec, this.responseSpec, loanIDWithoutEmi); - LoanStatusChecker.verifyLoanIsPending(loanStatusMap); - - System.out - .println("-----------------------------------APPROVE LOAN-----------------------------------------------------------"); - loanStatusHashMap = this.loanTransactionHelper - .approveLoanWithApproveAmount("01 June 2015", "01 June 2015", - "10000", loanIDWithoutEmi, createTranches); - LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); - LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap); - System.out - .println("-----------------------------------MULTI DISBURSAL LOAN WITHOUT EMI APPROVED SUCCESSFULLY---------------------------------------"); - - } - - private void validateRepaymentScheduleWithEMI(ArrayList periods){ - LoanDisbursementTestBuilder expectedRepaymentSchedule0 = new LoanDisbursementTestBuilder( - "[2015, 6, 1]", 0.0f, 0.0f, null, null, 5000.0f, null, null, - null); - - LoanDisbursementTestBuilder expectedRepaymentSchedule1 = new LoanDisbursementTestBuilder( - "[2015, 7, 1]", 800.0f, 800.0f, 50.0f, 750.0f, 4250.0f, 750.0f, - 750.0f, "[2015, 6, 1]"); - - LoanDisbursementTestBuilder expectedRepaymentSchedule2 = new LoanDisbursementTestBuilder( - "[2015, 8, 1]", 800.0f, 800.0f, 42.5f, 757.5f, 3492.5f, 757.5f, - 757.5f, "[2015, 7, 1]"); - - LoanDisbursementTestBuilder expectedRepaymentSchedule3 = new LoanDisbursementTestBuilder( - "[2015, 9, 1]", 0.0f, 0.0f, null, null, 5000.0f, null, null, null); - - LoanDisbursementTestBuilder expectedRepaymentSchedule4 = new LoanDisbursementTestBuilder( - "[2015, 9, 1]", 800.0f, 800.0f, 34.92f, 765.08f, 7727.42f, - 765.08f, 765.08f, "[2015, 8, 1]"); - - LoanDisbursementTestBuilder expectedRepaymentSchedule5 = new LoanDisbursementTestBuilder( - "[2015, 10, 1]", 800.0f, 800.0f, 77.27f, 722.73f, 7004.69f, - 722.73f, 722.73f, "[2015, 9, 1]"); - - LoanDisbursementTestBuilder expectedRepaymentSchedule6 = new LoanDisbursementTestBuilder( - "[2015, 11, 1]", 800.0f, 800.0f, 70.05f, 729.95f, 6274.74f, - 729.95f, 729.95f, "[2015, 10, 1]"); - - LoanDisbursementTestBuilder expectedRepaymentSchedule7 = new LoanDisbursementTestBuilder( - "[2015, 12, 1]", 800.0f, 800.0f, 62.75f, 737.25f, 5537.49f, - 737.25f, 737.25f, "[2015, 11, 1]"); - - LoanDisbursementTestBuilder expectedRepaymentSchedule8 = new LoanDisbursementTestBuilder( - "[2016, 1, 1]", 800.0f, 800.0f, 55.37f, 744.63f, 4792.86f, - 744.63f, 744.63f, "[2015, 12, 1]"); - - LoanDisbursementTestBuilder expectedRepaymentSchedule9 = new LoanDisbursementTestBuilder( - "[2016, 2, 1]", 800.0f, 800.0f, 47.93f, 752.07f, 4040.79f, - 752.07f, 752.07f, "[2016, 1, 1]"); - - LoanDisbursementTestBuilder expectedRepaymentSchedule10 = new LoanDisbursementTestBuilder( - "[2016, 3, 1]", 800.0f, 800.0f, 40.41f, 759.59f, 3281.2f, - 759.59f, 759.59f, "[2016, 2, 1]"); - - LoanDisbursementTestBuilder expectedRepaymentSchedule11 = new LoanDisbursementTestBuilder( - "[2016, 4, 1]", 800.0f, 800.0f, 32.81f, 767.19f, 2514.01f, - 767.19f, 767.19f, "[2016, 3, 1]"); - - LoanDisbursementTestBuilder expectedRepaymentSchedule12 = new LoanDisbursementTestBuilder( - "[2016, 5, 1]", 800.0f, 800.0f, 25.14f, 774.86f, 1739.15f, - 774.86f, 774.86f, "[2016, 4, 1]"); - - LoanDisbursementTestBuilder expectedRepaymentSchedule13 = new LoanDisbursementTestBuilder( - "[2016, 6, 1]", 800.0f, 800.0f, 17.39f, 782.61f, 956.54f, - 782.61f, 782.61f, "[2016, 5, 1]"); - - LoanDisbursementTestBuilder expectedRepaymentSchedule14 = new LoanDisbursementTestBuilder( - "[2016, 7, 1]", 966.11f, 966.11f, 9.57f, 956.54f, 0.0f, - 956.54f, 956.54f, "[2016, 6, 1]"); - - ArrayList list = new ArrayList(); - list.add(expectedRepaymentSchedule0); - list.add(expectedRepaymentSchedule1); - list.add(expectedRepaymentSchedule2); - list.add(expectedRepaymentSchedule3); - list.add(expectedRepaymentSchedule4); - list.add(expectedRepaymentSchedule5); - list.add(expectedRepaymentSchedule6); - list.add(expectedRepaymentSchedule7); - list.add(expectedRepaymentSchedule8); - list.add(expectedRepaymentSchedule9); - list.add(expectedRepaymentSchedule10); - list.add(expectedRepaymentSchedule11); - list.add(expectedRepaymentSchedule12); - list.add(expectedRepaymentSchedule13); - list.add(expectedRepaymentSchedule14); - - for (int i = 0; i < list.size(); i++) { - this.assertRepaymentScheduleValuesWithEMI(periods.get(i), list.get(i), i); - } - } - - private void assertRepaymentScheduleValuesWithEMI(HashMap period, - LoanDisbursementTestBuilder expectedRepaymentSchedule, int position) { - - assertEquals(period.get("dueDate").toString(), - expectedRepaymentSchedule.getDueDate()); - assertEquals(period.get("principalLoanBalanceOutstanding"), - expectedRepaymentSchedule.getPrincipalLoanBalanceOutstanding()); - assertEquals(period.get("totalOriginalDueForPeriod"), - expectedRepaymentSchedule.getTotalOriginalDueForPeriod()); - assertEquals(period.get("totalOutstandingForPeriod"), - expectedRepaymentSchedule.getTotalOutstandingForPeriod()); - - if (position != 0 && position != 3) { - - assertEquals(period.get("interestOutstanding"), - expectedRepaymentSchedule.getInterestOutstanding()); - assertEquals(period.get("principalOutstanding"), - expectedRepaymentSchedule.getPrincipalOutstanding()); - assertEquals(period.get("principalDue"), - expectedRepaymentSchedule.getPrincipalDue()); - assertEquals(period.get("principalOriginalDue"), - expectedRepaymentSchedule.getPrincipalOriginalDue()); - assertEquals(period.get("fromDate").toString(), - expectedRepaymentSchedule.getFromDate()); - } - } - - /* Uncomment and modify test builder values once MIFOSX-2006 is closed.*/ - /*private void validateRepaymentScheduleWithoutEMI(ArrayList periods){ - LoanDisbursementTestBuilder expectedRepaymentSchedule0 = new LoanDisbursementTestBuilder( - "[2015, 6, 1]", 0.0f, 0.0f, null, null, 5000.0f, null, null, - null); - - LoanDisbursementTestBuilder expectedRepaymentSchedule1 = new LoanDisbursementTestBuilder( - "[2015, 7, 1]", 800.0f, 800.0f, 50.0f, 750.0f, 4250.0f, 750.0f, - 750.0f, "[2015, 6, 1]"); - - LoanDisbursementTestBuilder expectedRepaymentSchedule2 = new LoanDisbursementTestBuilder( - "[2015, 8, 1]", 800.0f, 800.0f, 42.5f, 757.5f, 3492.5f, 757.5f, - 757.5f, "[2015, 7, 1]"); - - LoanDisbursementTestBuilder expectedRepaymentSchedule3 = new LoanDisbursementTestBuilder( - "[2015, 9, 1]", 0.0f, 0.0f, null, null, 5000.0f, null, null, null); - - LoanDisbursementTestBuilder expectedRepaymentSchedule4 = new LoanDisbursementTestBuilder( - "[2015, 9, 1]", 800.0f, 800.0f, 34.92f, 765.08f, 7727.42f, - 765.08f, 765.08f, "[2015, 8, 1]"); - - LoanDisbursementTestBuilder expectedRepaymentSchedule5 = new LoanDisbursementTestBuilder( - "[2015, 10, 1]", 800.0f, 800.0f, 77.27f, 722.73f, 7004.69f, - 722.73f, 722.73f, "[2015, 9, 1]"); - - LoanDisbursementTestBuilder expectedRepaymentSchedule6 = new LoanDisbursementTestBuilder( - "[2015, 11, 1]", 800.0f, 800.0f, 70.05f, 729.95f, 6274.74f, - 729.95f, 729.95f, "[2015, 10, 1]"); - - LoanDisbursementTestBuilder expectedRepaymentSchedule7 = new LoanDisbursementTestBuilder( - "[2015, 12, 1]", 800.0f, 800.0f, 62.75f, 737.25f, 5537.49f, - 737.25f, 737.25f, "[2015, 11, 1]"); - - LoanDisbursementTestBuilder expectedRepaymentSchedule8 = new LoanDisbursementTestBuilder( - "[2016, 1, 1]", 800.0f, 800.0f, 55.37f, 744.63f, 4792.86f, - 744.63f, 744.63f, "[2015, 12, 1]"); - - LoanDisbursementTestBuilder expectedRepaymentSchedule9 = new LoanDisbursementTestBuilder( - "[2016, 2, 1]", 800.0f, 800.0f, 47.93f, 752.07f, 4040.79f, - 752.07f, 752.07f, "[2016, 1, 1]"); - - LoanDisbursementTestBuilder expectedRepaymentSchedule10 = new LoanDisbursementTestBuilder( - "[2016, 3, 1]", 800.0f, 800.0f, 40.41f, 759.59f, 3281.2f, - 759.59f, 759.59f, "[2016, 2, 1]"); - - LoanDisbursementTestBuilder expectedRepaymentSchedule11 = new LoanDisbursementTestBuilder( - "[2016, 4, 1]", 800.0f, 800.0f, 32.81f, 767.19f, 2514.01f, - 767.19f, 767.19f, "[2016, 3, 1]"); - - LoanDisbursementTestBuilder expectedRepaymentSchedule12 = new LoanDisbursementTestBuilder( - "[2016, 5, 1]", 800.0f, 800.0f, 25.14f, 774.86f, 1739.15f, - 774.86f, 774.86f, "[2016, 4, 1]"); - - LoanDisbursementTestBuilder expectedRepaymentSchedule13 = new LoanDisbursementTestBuilder( - "[2016, 6, 1]", 800.0f, 800.0f, 17.39f, 782.61f, 956.54f, - 782.61f, 782.61f, "[2016, 5, 1]"); - - LoanDisbursementTestBuilder expectedRepaymentSchedule14 = new LoanDisbursementTestBuilder( - "[2016, 7, 1]", 966.11f, 966.11f, 9.57f, 956.54f, 0.0f, - 956.54f, 956.54f, "[2016, 6, 1]"); - - ArrayList list = new ArrayList(); - list.add(expectedRepaymentSchedule0); - list.add(expectedRepaymentSchedule1); - list.add(expectedRepaymentSchedule2); - list.add(expectedRepaymentSchedule3); - list.add(expectedRepaymentSchedule4); - list.add(expectedRepaymentSchedule5); - list.add(expectedRepaymentSchedule6); - list.add(expectedRepaymentSchedule7); - list.add(expectedRepaymentSchedule8); - list.add(expectedRepaymentSchedule9); - list.add(expectedRepaymentSchedule10); - list.add(expectedRepaymentSchedule11); - list.add(expectedRepaymentSchedule12); - list.add(expectedRepaymentSchedule13); - list.add(expectedRepaymentSchedule14); - - for (int i = 0; i < list.size(); i++) { - this.assertRepaymentScheduleValuesWithoutEMI(periods.get(i), list.get(i), i); - } - } - - private void assertRepaymentScheduleValuesWithoutEMI(HashMap period, - LoanDisbursementTestBuilder expectedRepaymentSchedule, int position) { - - assertEquals(period.get("dueDate").toString(), - expectedRepaymentSchedule.getDueDate()); - assertEquals(period.get("principalLoanBalanceOutstanding"), - expectedRepaymentSchedule.getPrincipalLoanBalanceOutstanding()); - assertEquals(period.get("totalOriginalDueForPeriod"), - expectedRepaymentSchedule.getTotalOriginalDueForPeriod()); - assertEquals(period.get("totalOutstandingForPeriod"), - expectedRepaymentSchedule.getTotalOutstandingForPeriod()); - - if (position != 0 && position != 3) { - - assertEquals(period.get("interestOutstanding"), - expectedRepaymentSchedule.getInterestOutstanding()); - assertEquals(period.get("principalOutstanding"), - expectedRepaymentSchedule.getPrincipalOutstanding()); - assertEquals(period.get("principalDue"), - expectedRepaymentSchedule.getPrincipalDue()); - assertEquals(period.get("principalOriginalDue"), - expectedRepaymentSchedule.getPrincipalOriginalDue()); - assertEquals(period.get("fromDate").toString(), - expectedRepaymentSchedule.getFromDate()); - } - } -*/ - private Integer applyForLoanApplicationWithEmiAmount( - final Integer clientID, final Integer loanProductID, - final String proposedAmount, List tranches, - final String installmentAmount) { - - System.out - .println("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------"); - final String loanApplicationJSON = new LoanApplicationTestBuilder() - // - .withPrincipal(proposedAmount) - // - .withLoanTermFrequency("12") - // - .withLoanTermFrequencyAsMonths() - // - .withNumberOfRepayments("12").withRepaymentEveryAfter("1") - .withRepaymentFrequencyTypeAsMonths() // - .withInterestRatePerPeriod("1") // - .withExpectedDisbursementDate("01 June 2015") // - .withTranches(tranches) // - .withFixedEmiAmount(installmentAmount) // - .withInterestTypeAsDecliningBalance() // - .withSubmittedOnDate("01 June 2015") // - .withAmortizationTypeAsEqualInstallments() // - .build(clientID.toString(), loanProductID.toString(), null); - - return this.loanTransactionHelper.getLoanId(loanApplicationJSON); - - } - - @Test - public void createApproveAndValidateMultiDisburseLoan() { - - List createTranches = new ArrayList<>(); - String id = null; - createTranches.add(this.loanTransactionHelper.createTrancheDetail(id, - "01 March 2014", "1000")); - - final Integer clientID = ClientHelper.createClient(this.requestSpec, - this.responseSpec, "01 January 2014"); - System.out - .println("---------------------------------CLIENT CREATED WITH ID---------------------------------------------------" - + clientID); - - final Integer loanProductID = this.loanTransactionHelper - .getLoanProductId(new LoanProductTestBuilder() - .withInterestTypeAsDecliningBalance() - .withTranches(true).build(null)); - System.out - .println("----------------------------------LOAN PRODUCT CREATED WITH ID-------------------------------------------" - + loanProductID); - - this.loanID = applyForLoanApplicationWithTranches(clientID, - loanProductID, proposedAmount, createTranches); - System.out - .println("-----------------------------------LOAN CREATED WITH LOANID-------------------------------------------------" - + loanID); - - HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan( - this.requestSpec, this.responseSpec, loanID); - LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap); - - System.out - .println("-----------------------------------APPROVE LOAN-----------------------------------------------------------"); - loanStatusHashMap = this.loanTransactionHelper - .approveLoanWithApproveAmount(approveDate, - expectedDisbursementDate, approvalAmount, loanID, - createTranches); - LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); - LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap); - System.out - .println("-----------------------------------MULTI DISBURSAL LOAN APPROVED SUCCESSFULLY---------------------------------------"); - ArrayList disbursementDetails = (ArrayList) this.loanTransactionHelper - .getLoanDetail(this.requestSpec, this.responseSpec, - this.loanID, "disbursementDetails"); - this.disbursementId = (Integer) disbursementDetails.get(0).get("id"); - this.editLoanDisbursementDetails(); - } - - private void editLoanDisbursementDetails() { - this.editDateAndPrincipalOfExistingTranche(); - this.addNewDisbursementDetails(); - this.deleteDisbursmentDetails(); - } - - private void addNewDisbursementDetails() { - List addTranches = new ArrayList<>(); - ArrayList disbursementDetails = (ArrayList) this.loanTransactionHelper - .getLoanDetail(this.requestSpec, this.responseSpec, - this.loanID, "disbursementDetails"); - ArrayList expectedDisbursementDate = (ArrayList) disbursementDetails - .get(0).get("expectedDisbursementDate"); - String date = formatExpectedDisbursementDate(expectedDisbursementDate - .toString()); - - String id = null; - addTranches.add(this.loanTransactionHelper.createTrancheDetail( - disbursementDetails.get(0).get("id").toString(), date, - disbursementDetails.get(0).get("principal").toString())); - addTranches.add(this.loanTransactionHelper.createTrancheDetail(id, - "3 March 2014", "2000")); - addTranches.add(this.loanTransactionHelper.createTrancheDetail(id, - "4 March 2014", "500")); - - /* Add disbursement detail */ - this.loanTransactionHelper.addAndDeleteDisbursementDetail(this.loanID, - this.approvalAmount, this.expectedDisbursementDate, - addTranches, ""); - } - - private void deleteDisbursmentDetails() { - List deleteTranches = new ArrayList<>(); - ArrayList disbursementDetails = (ArrayList) this.loanTransactionHelper - .getLoanDetail(this.requestSpec, this.responseSpec, - this.loanID, "disbursementDetails"); - /* Delete the last tranche */ - for (int i = 0; i < disbursementDetails.size() - 1; i++) { - ArrayList expectedDisbursementDate = (ArrayList) disbursementDetails - .get(i).get("expectedDisbursementDate"); - String disbursementDate = formatExpectedDisbursementDate(expectedDisbursementDate - .toString()); - deleteTranches.add(this.loanTransactionHelper.createTrancheDetail( - disbursementDetails.get(i).get("id").toString(), - disbursementDate, - disbursementDetails.get(i).get("principal").toString())); - } - - /* Add disbursement detail */ - this.loanTransactionHelper.addAndDeleteDisbursementDetail(this.loanID, - this.approvalAmount, this.expectedDisbursementDate, - deleteTranches, ""); - } - - private void editDateAndPrincipalOfExistingTranche() { - String updatedExpectedDisbursementDate = "01 March 2014"; - String updatedPrincipal = "900"; - /* Update */ - this.loanTransactionHelper.editDisbursementDetail(this.loanID, - this.disbursementId, this.approvalAmount, - this.expectedDisbursementDate, updatedExpectedDisbursementDate, - updatedPrincipal, ""); - /* Validate Edit */ - ArrayList disbursementDetails = (ArrayList) this.loanTransactionHelper - .getLoanDetail(this.requestSpec, this.responseSpec, - this.loanID, "disbursementDetails"); - assertEquals(Float.valueOf(updatedPrincipal), disbursementDetails - .get(0).get("principal")); - ArrayList expectedDisbursementDate = (ArrayList) disbursementDetails - .get(0).get("expectedDisbursementDate"); - String date = formatExpectedDisbursementDate(expectedDisbursementDate - .toString()); - assertEquals(updatedExpectedDisbursementDate, date); - - } - - private String formatExpectedDisbursementDate( - String expectedDisbursementDate) { - - SimpleDateFormat source = new SimpleDateFormat("[yyyy, MM, dd]"); - SimpleDateFormat target = new SimpleDateFormat("dd MMMM yyyy"); - String date = null; - try { - date = target.format(source.parse(expectedDisbursementDate)); - } catch (ParseException e) { - e.printStackTrace(); - } - return date; - } - - private Integer applyForLoanApplicationWithTranches(final Integer clientID, - final Integer loanProductID, String principal, - List tranches) { - System.out - .println("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------"); - final String loanApplicationJSON = new LoanApplicationTestBuilder() - // - .withPrincipal(principal) - // - .withLoanTermFrequency("5") - // - .withLoanTermFrequencyAsMonths() - // - .withNumberOfRepayments("5").withRepaymentEveryAfter("1") - .withRepaymentFrequencyTypeAsMonths() // - .withInterestRatePerPeriod("2") // - .withExpectedDisbursementDate("01 March 2014") // - .withTranches(tranches) // - .withInterestTypeAsDecliningBalance() // - .withSubmittedOnDate("01 March 2014") // - .build(clientID.toString(), loanProductID.toString(), null); - - return this.loanTransactionHelper.getLoanId(loanApplicationJSON); - } + private ResponseSpecification responseSpec; + private RequestSpecification requestSpec; + private LoanTransactionHelper loanTransactionHelper; + private Integer loanID; + private Integer disbursementId; + final String approveDate = "01 March 2014"; + final String expectedDisbursementDate = "01 March 2014"; + final String proposedAmount = "5000"; + final String approvalAmount = "5000"; + + @Before + public void setup() { + Utils.initializeRESTAssured(); + this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); + this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); + this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); + this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec); + } + + @Test + public void createAndValidateMultiDisburseLoansBasedOnEmi() { + List createTranches = new ArrayList<>(); + String id = null; + String installmentAmount = "800"; + String withoutInstallmentAmount = ""; + String proposedAmount = "10000"; + createTranches.add(this.loanTransactionHelper.createTrancheDetail(id, "01 June 2015", "5000")); + createTranches.add(this.loanTransactionHelper.createTrancheDetail(id, "01 Sep 2015", "5000")); + + final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2014"); + System.out.println( + "---------------------------------CLIENT CREATED WITH ID---------------------------------------------------" + clientID); + + final Integer loanProductID = this.loanTransactionHelper + .getLoanProductId(new LoanProductTestBuilder().withInterestTypeAsDecliningBalance().withMoratorium("", "") + .withAmortizationTypeAsEqualInstallments().withTranches(true).build(null)); + System.out.println("----------------------------------LOAN PRODUCT CREATED WITH ID-------------------------------------------" + + loanProductID); + + final Integer loanIDWithEmi = applyForLoanApplicationWithEmiAmount(clientID, loanProductID, proposedAmount, createTranches, + installmentAmount); + + System.out + .println("-----------------------------------LOAN CREATED WITH EMI LOANID-------------------------------------------------" + + loanIDWithEmi); + + HashMap repaymentScheduleWithEmi = (HashMap) this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, + loanIDWithEmi, "repaymentSchedule"); + + ArrayList periods = (ArrayList) repaymentScheduleWithEmi.get("periods"); + assertEquals(periods.size(), 15); + + this.validateRepaymentScheduleWithEMI(periods); + + HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanIDWithEmi); + LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap); + + System.out.println("-----------------------------------APPROVE LOAN-----------------------------------------------------------"); + loanStatusHashMap = this.loanTransactionHelper.approveLoanWithApproveAmount("01 June 2015", "01 June 2015", "10000", loanIDWithEmi, + createTranches); + LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); + LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap); + System.out.println( + "-----------------------------------MULTI DISBURSAL LOAN WITH EMI APPROVED SUCCESSFULLY---------------------------------------"); + + final Integer loanIDWithoutEmi = applyForLoanApplicationWithEmiAmount(clientID, loanProductID, proposedAmount, createTranches, + withoutInstallmentAmount); + + HashMap repaymentScheduleWithoutEmi = (HashMap) this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, + loanIDWithoutEmi, "repaymentSchedule"); + + ArrayList periods1 = (ArrayList) repaymentScheduleWithEmi.get("periods"); + assertEquals(periods1.size(), 15); + + System.out.println( + "-----------------------------------LOAN CREATED WITHOUT EMI LOANID-------------------------------------------------" + + loanIDWithoutEmi); + + /* To be uncommented once issue MIFOSX-2006 is closed. */ + // this.validateRepaymentScheduleWithoutEMI(periods1); + + HashMap loanStatusMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanIDWithoutEmi); + LoanStatusChecker.verifyLoanIsPending(loanStatusMap); + + System.out.println("-----------------------------------APPROVE LOAN-----------------------------------------------------------"); + loanStatusHashMap = this.loanTransactionHelper.approveLoanWithApproveAmount("01 June 2015", "01 June 2015", "10000", + loanIDWithoutEmi, createTranches); + LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); + LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap); + System.out.println( + "-----------------------------------MULTI DISBURSAL LOAN WITHOUT EMI APPROVED SUCCESSFULLY---------------------------------------"); + + } + + private void validateRepaymentScheduleWithEMI(ArrayList periods) { + LoanDisbursementTestBuilder expectedRepaymentSchedule0 = new LoanDisbursementTestBuilder("[2015, 6, 1]", 0.0f, 0.0f, null, null, + 5000.0f, null, null, null); + + LoanDisbursementTestBuilder expectedRepaymentSchedule1 = new LoanDisbursementTestBuilder("[2015, 7, 1]", 800f, 800.0f, 50.0f, + 750.0f, 4250.0f, 750.0f, 750.0f, "[2015, 6, 1]"); + + LoanDisbursementTestBuilder expectedRepaymentSchedule2 = new LoanDisbursementTestBuilder("[2015, 8, 1]", 800.0f, 800.0f, 42.5f, + 757.5f, 3492.5f, 757.5f, 757.5f, "[2015, 7, 1]"); + + LoanDisbursementTestBuilder expectedRepaymentSchedule3 = new LoanDisbursementTestBuilder("[2015, 9, 1]", 0.0f, 0.0f, null, null, + 5000.0f, null, null, null); + + LoanDisbursementTestBuilder expectedRepaymentSchedule4 = new LoanDisbursementTestBuilder("[2015, 9, 1]", 800.0f, 800.0f, 34.92f, + 765.08f, 7727.42f, 765.08f, 765.08f, "[2015, 8, 1]"); + + LoanDisbursementTestBuilder expectedRepaymentSchedule5 = new LoanDisbursementTestBuilder("[2015, 10, 1]", 800.0f, 800.0f, 77.27f, + 722.73f, 7004.69f, 722.73f, 722.73f, "[2015, 9, 1]"); + + LoanDisbursementTestBuilder expectedRepaymentSchedule6 = new LoanDisbursementTestBuilder("[2015, 11, 1]", 800.0f, 800.0f, 70.05f, + 729.95f, 6274.74f, 729.95f, 729.95f, "[2015, 10, 1]"); + + LoanDisbursementTestBuilder expectedRepaymentSchedule7 = new LoanDisbursementTestBuilder("[2015, 12, 1]", 800.0f, 800.0f, 62.75f, + 737.25f, 5537.49f, 737.25f, 737.25f, "[2015, 11, 1]"); + + LoanDisbursementTestBuilder expectedRepaymentSchedule8 = new LoanDisbursementTestBuilder("[2016, 1, 1]", 800.0f, 800.0f, 55.37f, + 744.63f, 4792.86f, 744.63f, 744.63f, "[2015, 12, 1]"); + + LoanDisbursementTestBuilder expectedRepaymentSchedule9 = new LoanDisbursementTestBuilder("[2016, 2, 1]", 800.0f, 800.0f, 47.93f, + 752.07f, 4040.79f, 752.07f, 752.07f, "[2016, 1, 1]"); + + LoanDisbursementTestBuilder expectedRepaymentSchedule10 = new LoanDisbursementTestBuilder("[2016, 3, 1]", 800.0f, 800.0f, 40.41f, + 759.59f, 3281.2f, 759.59f, 759.59f, "[2016, 2, 1]"); + + LoanDisbursementTestBuilder expectedRepaymentSchedule11 = new LoanDisbursementTestBuilder("[2016, 4, 1]", 800.0f, 800.0f, 32.81f, + 767.19f, 2514.01f, 767.19f, 767.19f, "[2016, 3, 1]"); + + LoanDisbursementTestBuilder expectedRepaymentSchedule12 = new LoanDisbursementTestBuilder("[2016, 5, 1]", 800.0f, 800.0f, 25.14f, + 774.86f, 1739.15f, 774.86f, 774.86f, "[2016, 4, 1]"); + + LoanDisbursementTestBuilder expectedRepaymentSchedule13 = new LoanDisbursementTestBuilder("[2016, 6, 1]", 800.0f, 800.0f, 17.39f, + 782.61f, 956.54f, 782.61f, 782.61f, "[2016, 5, 1]"); + + LoanDisbursementTestBuilder expectedRepaymentSchedule14 = new LoanDisbursementTestBuilder("[2016, 7, 1]", 966.11f, 966.11f, 9.57f, + 956.54f, 0.0f, 956.54f, 956.54f, "[2016, 6, 1]"); + + ArrayList list = new ArrayList(); + list.add(expectedRepaymentSchedule0); + list.add(expectedRepaymentSchedule1); + list.add(expectedRepaymentSchedule2); + list.add(expectedRepaymentSchedule3); + list.add(expectedRepaymentSchedule4); + list.add(expectedRepaymentSchedule5); + list.add(expectedRepaymentSchedule6); + list.add(expectedRepaymentSchedule7); + list.add(expectedRepaymentSchedule8); + list.add(expectedRepaymentSchedule9); + list.add(expectedRepaymentSchedule10); + list.add(expectedRepaymentSchedule11); + list.add(expectedRepaymentSchedule12); + list.add(expectedRepaymentSchedule13); + list.add(expectedRepaymentSchedule14); + + for (int i = 0; i < list.size(); i++) { + this.assertRepaymentScheduleValuesWithEMI(periods.get(i), list.get(i), i); + } + } + + private void assertRepaymentScheduleValuesWithEMI(HashMap period, LoanDisbursementTestBuilder expectedRepaymentSchedule, int position) { + + assertEquals(period.get("dueDate").toString(), expectedRepaymentSchedule.getDueDate()); + assertEquals(period.get("principalLoanBalanceOutstanding"), expectedRepaymentSchedule.getPrincipalLoanBalanceOutstanding()); + System.out.println(period.get("totalOriginalDueForPeriod").toString()); + assertEquals(new Float(period.get("totalOriginalDueForPeriod").toString()), + expectedRepaymentSchedule.getTotalOriginalDueForPeriod().floatValue(), 0.0f); + + assertEquals(new Float(period.get("totalOutstandingForPeriod").toString()).floatValue(), + expectedRepaymentSchedule.getTotalOutstandingForPeriod(), 0.0f); + + if (position != 0 && position != 3) { + + assertEquals(new Float(period.get("interestOutstanding").toString()).floatValue(), + expectedRepaymentSchedule.getInterestOutstanding(), 0.0f); + assertEquals(new Float(period.get("principalOutstanding").toString()).floatValue(), + expectedRepaymentSchedule.getPrincipalOutstanding(), 0.0f); + assertEquals(new Float(period.get("principalDue").toString()).floatValue(), expectedRepaymentSchedule.getPrincipalDue(), 0.0f); + assertEquals(new Float(period.get("principalOriginalDue").toString()).floatValue(), + expectedRepaymentSchedule.getPrincipalOriginalDue(), 0.0f); + assertEquals(period.get("fromDate").toString(), expectedRepaymentSchedule.getFromDate()); + } + } + + /* Uncomment and modify test builder values once MIFOSX-2006 is closed. */ + /* + * private void validateRepaymentScheduleWithoutEMI(ArrayList + * periods){ LoanDisbursementTestBuilder expectedRepaymentSchedule0 = new + * LoanDisbursementTestBuilder( "[2015, 6, 1]", 0.0f, 0.0f, null, null, + * 5000.0f, null, null, null); + * + * LoanDisbursementTestBuilder expectedRepaymentSchedule1 = new + * LoanDisbursementTestBuilder( "[2015, 7, 1]", 800.0f, 800.0f, 50.0f, + * 750.0f, 4250.0f, 750.0f, 750.0f, "[2015, 6, 1]"); + * + * LoanDisbursementTestBuilder expectedRepaymentSchedule2 = new + * LoanDisbursementTestBuilder( "[2015, 8, 1]", 800.0f, 800.0f, 42.5f, + * 757.5f, 3492.5f, 757.5f, 757.5f, "[2015, 7, 1]"); + * + * LoanDisbursementTestBuilder expectedRepaymentSchedule3 = new + * LoanDisbursementTestBuilder( "[2015, 9, 1]", 0.0f, 0.0f, null, null, + * 5000.0f, null, null, null); + * + * LoanDisbursementTestBuilder expectedRepaymentSchedule4 = new + * LoanDisbursementTestBuilder( "[2015, 9, 1]", 800.0f, 800.0f, 34.92f, + * 765.08f, 7727.42f, 765.08f, 765.08f, "[2015, 8, 1]"); + * + * LoanDisbursementTestBuilder expectedRepaymentSchedule5 = new + * LoanDisbursementTestBuilder( "[2015, 10, 1]", 800.0f, 800.0f, 77.27f, + * 722.73f, 7004.69f, 722.73f, 722.73f, "[2015, 9, 1]"); + * + * LoanDisbursementTestBuilder expectedRepaymentSchedule6 = new + * LoanDisbursementTestBuilder( "[2015, 11, 1]", 800.0f, 800.0f, 70.05f, + * 729.95f, 6274.74f, 729.95f, 729.95f, "[2015, 10, 1]"); + * + * LoanDisbursementTestBuilder expectedRepaymentSchedule7 = new + * LoanDisbursementTestBuilder( "[2015, 12, 1]", 800.0f, 800.0f, 62.75f, + * 737.25f, 5537.49f, 737.25f, 737.25f, "[2015, 11, 1]"); + * + * LoanDisbursementTestBuilder expectedRepaymentSchedule8 = new + * LoanDisbursementTestBuilder( "[2016, 1, 1]", 800.0f, 800.0f, 55.37f, + * 744.63f, 4792.86f, 744.63f, 744.63f, "[2015, 12, 1]"); + * + * LoanDisbursementTestBuilder expectedRepaymentSchedule9 = new + * LoanDisbursementTestBuilder( "[2016, 2, 1]", 800.0f, 800.0f, 47.93f, + * 752.07f, 4040.79f, 752.07f, 752.07f, "[2016, 1, 1]"); + * + * LoanDisbursementTestBuilder expectedRepaymentSchedule10 = new + * LoanDisbursementTestBuilder( "[2016, 3, 1]", 800.0f, 800.0f, 40.41f, + * 759.59f, 3281.2f, 759.59f, 759.59f, "[2016, 2, 1]"); + * + * LoanDisbursementTestBuilder expectedRepaymentSchedule11 = new + * LoanDisbursementTestBuilder( "[2016, 4, 1]", 800.0f, 800.0f, 32.81f, + * 767.19f, 2514.01f, 767.19f, 767.19f, "[2016, 3, 1]"); + * + * LoanDisbursementTestBuilder expectedRepaymentSchedule12 = new + * LoanDisbursementTestBuilder( "[2016, 5, 1]", 800.0f, 800.0f, 25.14f, + * 774.86f, 1739.15f, 774.86f, 774.86f, "[2016, 4, 1]"); + * + * LoanDisbursementTestBuilder expectedRepaymentSchedule13 = new + * LoanDisbursementTestBuilder( "[2016, 6, 1]", 800.0f, 800.0f, 17.39f, + * 782.61f, 956.54f, 782.61f, 782.61f, "[2016, 5, 1]"); + * + * LoanDisbursementTestBuilder expectedRepaymentSchedule14 = new + * LoanDisbursementTestBuilder( "[2016, 7, 1]", 966.11f, 966.11f, 9.57f, + * 956.54f, 0.0f, 956.54f, 956.54f, "[2016, 6, 1]"); + * + * ArrayList list = new + * ArrayList(); + * list.add(expectedRepaymentSchedule0); + * list.add(expectedRepaymentSchedule1); + * list.add(expectedRepaymentSchedule2); + * list.add(expectedRepaymentSchedule3); + * list.add(expectedRepaymentSchedule4); + * list.add(expectedRepaymentSchedule5); + * list.add(expectedRepaymentSchedule6); + * list.add(expectedRepaymentSchedule7); + * list.add(expectedRepaymentSchedule8); + * list.add(expectedRepaymentSchedule9); + * list.add(expectedRepaymentSchedule10); + * list.add(expectedRepaymentSchedule11); + * list.add(expectedRepaymentSchedule12); + * list.add(expectedRepaymentSchedule13); + * list.add(expectedRepaymentSchedule14); + * + * for (int i = 0; i < list.size(); i++) { + * this.assertRepaymentScheduleValuesWithoutEMI(periods.get(i), list.get(i), + * i); } } + * + * private void assertRepaymentScheduleValuesWithoutEMI(HashMap period, + * LoanDisbursementTestBuilder expectedRepaymentSchedule, int position) { + * + * assertEquals(period.get("dueDate").toString(), + * expectedRepaymentSchedule.getDueDate()); + * assertEquals(period.get("principalLoanBalanceOutstanding"), + * expectedRepaymentSchedule.getPrincipalLoanBalanceOutstanding()); + * assertEquals(period.get("totalOriginalDueForPeriod"), + * expectedRepaymentSchedule.getTotalOriginalDueForPeriod()); + * assertEquals(period.get("totalOutstandingForPeriod"), + * expectedRepaymentSchedule.getTotalOutstandingForPeriod()); + * + * if (position != 0 && position != 3) { + * + * assertEquals(period.get("interestOutstanding"), + * expectedRepaymentSchedule.getInterestOutstanding()); + * assertEquals(period.get("principalOutstanding"), + * expectedRepaymentSchedule.getPrincipalOutstanding()); + * assertEquals(period.get("principalDue"), + * expectedRepaymentSchedule.getPrincipalDue()); + * assertEquals(period.get("principalOriginalDue"), + * expectedRepaymentSchedule.getPrincipalOriginalDue()); + * assertEquals(period.get("fromDate").toString(), + * expectedRepaymentSchedule.getFromDate()); } } + */ + private Integer applyForLoanApplicationWithEmiAmount(final Integer clientID, final Integer loanProductID, final String proposedAmount, + List tranches, final String installmentAmount) { + + System.out.println("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------"); + final String loanApplicationJSON = new LoanApplicationTestBuilder() + // + .withPrincipal(proposedAmount) + // + .withLoanTermFrequency("12") + // + .withLoanTermFrequencyAsMonths() + // + .withNumberOfRepayments("12").withRepaymentEveryAfter("1").withRepaymentFrequencyTypeAsMonths() // + .withInterestRatePerPeriod("1") // + .withExpectedDisbursementDate("01 June 2015") // + .withTranches(tranches) // + .withFixedEmiAmount(installmentAmount) // + .withInterestTypeAsDecliningBalance() // + .withSubmittedOnDate("01 June 2015") // + .withAmortizationTypeAsEqualInstallments() // + .build(clientID.toString(), loanProductID.toString(), null); + + return this.loanTransactionHelper.getLoanId(loanApplicationJSON); + + } + + @Test + public void createApproveAndValidateMultiDisburseLoan() { + + List createTranches = new ArrayList<>(); + String id = null; + createTranches.add(this.loanTransactionHelper.createTrancheDetail(id, "01 March 2014", "1000")); + + final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2014"); + System.out.println( + "---------------------------------CLIENT CREATED WITH ID---------------------------------------------------" + clientID); + + final Integer loanProductID = this.loanTransactionHelper + .getLoanProductId(new LoanProductTestBuilder().withInterestTypeAsDecliningBalance().withTranches(true).build(null)); + System.out.println("----------------------------------LOAN PRODUCT CREATED WITH ID-------------------------------------------" + + loanProductID); + + this.loanID = applyForLoanApplicationWithTranches(clientID, loanProductID, proposedAmount, createTranches); + System.out.println( + "-----------------------------------LOAN CREATED WITH LOANID-------------------------------------------------" + loanID); + + HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID); + LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap); + + System.out.println("-----------------------------------APPROVE LOAN-----------------------------------------------------------"); + loanStatusHashMap = this.loanTransactionHelper.approveLoanWithApproveAmount(approveDate, expectedDisbursementDate, approvalAmount, + loanID, createTranches); + LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); + LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap); + System.out.println( + "-----------------------------------MULTI DISBURSAL LOAN APPROVED SUCCESSFULLY---------------------------------------"); + ArrayList disbursementDetails = (ArrayList) this.loanTransactionHelper.getLoanDetail(this.requestSpec, + this.responseSpec, this.loanID, "disbursementDetails"); + this.disbursementId = (Integer) disbursementDetails.get(0).get("id"); + this.editLoanDisbursementDetails(); + } + + private void editLoanDisbursementDetails() { + this.editDateAndPrincipalOfExistingTranche(); + this.addNewDisbursementDetails(); + this.deleteDisbursmentDetails(); + } + + private void addNewDisbursementDetails() { + List addTranches = new ArrayList<>(); + ArrayList disbursementDetails = (ArrayList) this.loanTransactionHelper.getLoanDetail(this.requestSpec, + this.responseSpec, this.loanID, "disbursementDetails"); + ArrayList expectedDisbursementDate = (ArrayList) disbursementDetails.get(0).get("expectedDisbursementDate"); + String date = formatExpectedDisbursementDate(expectedDisbursementDate.toString()); + + String id = null; + addTranches.add(this.loanTransactionHelper.createTrancheDetail(disbursementDetails.get(0).get("id").toString(), date, + disbursementDetails.get(0).get("principal").toString())); + addTranches.add(this.loanTransactionHelper.createTrancheDetail(id, "3 March 2014", "2000")); + addTranches.add(this.loanTransactionHelper.createTrancheDetail(id, "4 March 2014", "500")); + + /* Add disbursement detail */ + this.loanTransactionHelper.addAndDeleteDisbursementDetail(this.loanID, this.approvalAmount, this.expectedDisbursementDate, + addTranches, ""); + } + + private void deleteDisbursmentDetails() { + List deleteTranches = new ArrayList<>(); + ArrayList disbursementDetails = (ArrayList) this.loanTransactionHelper.getLoanDetail(this.requestSpec, + this.responseSpec, this.loanID, "disbursementDetails"); + /* Delete the last tranche */ + for (int i = 0; i < disbursementDetails.size() - 1; i++) { + ArrayList expectedDisbursementDate = (ArrayList) disbursementDetails.get(i).get("expectedDisbursementDate"); + String disbursementDate = formatExpectedDisbursementDate(expectedDisbursementDate.toString()); + deleteTranches.add(this.loanTransactionHelper.createTrancheDetail(disbursementDetails.get(i).get("id").toString(), + disbursementDate, disbursementDetails.get(i).get("principal").toString())); + } + + /* Add disbursement detail */ + this.loanTransactionHelper.addAndDeleteDisbursementDetail(this.loanID, this.approvalAmount, this.expectedDisbursementDate, + deleteTranches, ""); + } + + private void editDateAndPrincipalOfExistingTranche() { + String updatedExpectedDisbursementDate = "01 March 2014"; + String updatedPrincipal = "900"; + /* Update */ + this.loanTransactionHelper.editDisbursementDetail(this.loanID, this.disbursementId, this.approvalAmount, + this.expectedDisbursementDate, updatedExpectedDisbursementDate, updatedPrincipal, ""); + /* Validate Edit */ + ArrayList disbursementDetails = (ArrayList) this.loanTransactionHelper.getLoanDetail(this.requestSpec, + this.responseSpec, this.loanID, "disbursementDetails"); + assertEquals(Float.valueOf(updatedPrincipal), disbursementDetails.get(0).get("principal")); + ArrayList expectedDisbursementDate = (ArrayList) disbursementDetails.get(0).get("expectedDisbursementDate"); + String date = formatExpectedDisbursementDate(expectedDisbursementDate.toString()); + assertEquals(updatedExpectedDisbursementDate, date); + + } + + private String formatExpectedDisbursementDate(String expectedDisbursementDate) { + + SimpleDateFormat source = new SimpleDateFormat("[yyyy, MM, dd]"); + SimpleDateFormat target = new SimpleDateFormat("dd MMMM yyyy"); + String date = null; + try { + date = target.format(source.parse(expectedDisbursementDate)); + } catch (ParseException e) { + e.printStackTrace(); + } + return date; + } + + private Integer applyForLoanApplicationWithTranches(final Integer clientID, final Integer loanProductID, String principal, + List tranches) { + System.out.println("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------"); + final String loanApplicationJSON = new LoanApplicationTestBuilder() + // + .withPrincipal(principal) + // + .withLoanTermFrequency("5") + // + .withLoanTermFrequencyAsMonths() + // + .withNumberOfRepayments("5").withRepaymentEveryAfter("1").withRepaymentFrequencyTypeAsMonths() // + .withInterestRatePerPeriod("2") // + .withExpectedDisbursementDate("01 March 2014") // + .withTranches(tranches) // + .withInterestTypeAsDecliningBalance() // + .withSubmittedOnDate("01 March 2014") // + .build(clientID.toString(), loanProductID.toString(), null); + + return this.loanTransactionHelper.getLoanId(loanApplicationJSON); + } } diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/ClientChargesTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/ClientChargesTest.java index 965fef0d5..0997ea912 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/ClientChargesTest.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/ClientChargesTest.java @@ -74,14 +74,15 @@ public class ClientChargesTest { final String clientChargePaidTransactionId = ClientHelper.payChargesForClients(this.requestSpec, this.responseSpec, clientId, clientChargeId, ClientHelper.getPayChargeJSON("25 AUGUST 2015", "10")); Assert.assertNotNull(clientChargePaidTransactionId); - isValidOutstandingAmount(ClientHelper.getClientCharge(requestSpec, responseSpec, clientId.toString()), (float) 190.0); + isValidOutstandingAmount(ClientHelper.getClientCharge(requestSpec, responseSpec, clientId.toString(), clientChargeId.toString()), + (float) 190.0); /** * Revert the paid client charge transaction by passing the * clientChargePaidTransactionId and ensure the same is reverted. */ - final Integer undoTrxnId = ClientHelper.revertClientChargeTransaction(this.requestSpec, this.responseSpec, clientId.toString(), - clientChargePaidTransactionId); + final Integer undoTrxnId = ClientHelper.revertClientChargeTransaction(this.requestSpec, this.responseSpec, + clientId.toString(), clientChargePaidTransactionId); Assert.assertNotNull(undoTrxnId); isReversedTransaction(clientId.toString(), undoTrxnId.toString()); /** @@ -103,8 +104,8 @@ public class ClientChargesTest { * waiveOffClientChargeTransactionId and ensured the transaction is * reversed. */ - final Integer undoWaiveTrxnId = ClientHelper.revertClientChargeTransaction(this.requestSpec, this.responseSpec, - clientId.toString(), waiveOffClientChargeTransactionId); + final Integer undoWaiveTrxnId = ClientHelper.revertClientChargeTransaction(this.requestSpec, this.responseSpec, clientId.toString(), + waiveOffClientChargeTransactionId); Assert.assertNotNull(undoWaiveTrxnId); isReversedTransaction(clientId.toString(), undoWaiveTrxnId.toString()); /** @@ -130,7 +131,8 @@ public class ClientChargesTest { clientChargeId, ClientHelper.getPayChargeJSON("25 AUGUST 2015", "100")); Assert.assertNotNull(chargePaid_responseId); - isValidOutstandingAmount(ClientHelper.getClientCharge(requestSpec, responseSpec, clientId.toString()), (float) 100.0); + isValidOutstandingAmount(ClientHelper.getClientCharge(requestSpec, responseSpec, clientId.toString(), clientChargeId.toString()), + (float) 100.0); } @@ -147,8 +149,8 @@ public class ClientChargesTest { } /** - * Check whether the outStandingAmount is equal to expected Amount or not after - * paying or after waiving off the client charge. + * Check whether the outStandingAmount is equal to expected Amount or not + * after paying or after waiving off the client charge. * * @param outStandingAmount * @param expectedAmount diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/ClientHelper.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/ClientHelper.java index 80ba4bfa9..b5bccd7dd 100755 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/ClientHelper.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/ClientHelper.java @@ -7,7 +7,6 @@ package org.mifosplatform.integrationtests.common; import static org.junit.Assert.assertEquals; -import java.util.ArrayList; import java.util.HashMap; import org.mifosplatform.integrationtests.common.system.CodeHelper; @@ -57,12 +56,12 @@ public class ClientHelper { "clientId"); } - public static Integer createClientForAccountPreference(final RequestSpecification requestSpec, - final ResponseSpecification responseSpec, final Integer clientType, String jsonAttributeToGetBack) { + public static Integer createClientForAccountPreference(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, + final Integer clientType, String jsonAttributeToGetBack) { final String activationDate = "04 March 2011"; final String officeId = "1"; - System.out - .println("---------------------------------CREATING A CLIENT BASED ON ACCOUNT PREFERENCE---------------------------------------------"); + System.out.println( + "---------------------------------CREATING A CLIENT BASED ON ACCOUNT PREFERENCE---------------------------------------------"); return Utils.performServerPost(requestSpec, responseSpec, CREATE_CLIENT_URL, getTestClientWithClientTypeAsJSON(activationDate, officeId, clientType.toString()), jsonAttributeToGetBack); } @@ -305,7 +304,7 @@ public class ClientHelper { final Integer clientId, final String request) { System.out.println("--------------------------------- ADD CHARGES FOR Client --------------------------------"); final String ADD_CHARGES_URL = "/mifosng-provider/api/v1/clients/" + clientId + "/charges?" + Utils.TENANT_IDENTIFIER; - final HashMap response = Utils.performServerPost(requestSpec, responseSpec, ADD_CHARGES_URL, request, ""); + final HashMap response = Utils.performServerPost(requestSpec, responseSpec, ADD_CHARGES_URL, request, ""); return (Integer) response.get("resourceId"); } @@ -314,7 +313,7 @@ public class ClientHelper { System.out.println("--------------------------------- PAY CHARGES FOR CLIENT --------------------------------"); final String CHARGES_URL = "/mifosng-provider/api/v1/clients/" + clientId + "/charges/" + clientChargeId + "?command=paycharge&" + Utils.TENANT_IDENTIFIER; - final HashMap response = Utils.performServerPost(requestSpec, responseSpec, CHARGES_URL, json, ""); + final HashMap response = Utils.performServerPost(requestSpec, responseSpec, CHARGES_URL, json, ""); return response.get("transactionId") != null ? response.get("transactionId").toString() : null; } @@ -324,7 +323,7 @@ public class ClientHelper { final String CHARGES_URL = "/mifosng-provider/api/v1/clients/" + clientId + "/charges/" + clientChargeId + "?command=waive&" + Utils.TENANT_IDENTIFIER; - final HashMap response = Utils.performServerPost(requestSpec, responseSpec, CHARGES_URL, json, ""); + final HashMap response = Utils.performServerPost(requestSpec, responseSpec, CHARGES_URL, json, ""); return response.get("transactionId").toString(); } @@ -334,17 +333,17 @@ public class ClientHelper { final String CHARGES_URL = "/mifosng-provider/api/v1/clients/" + clientId + "/transactions/" + clientChargeId + "?command=undo&" + Utils.TENANT_IDENTIFIER; - final HashMap response = Utils.performServerPost(requestSpec, responseSpec, CHARGES_URL, "", ""); + final HashMap response = Utils.performServerPost(requestSpec, responseSpec, CHARGES_URL, "", ""); return (Integer) response.get("resourceId"); } public static Object getClientCharge(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, - final String clientId) { + final String clientId, final String clientChargeId) { System.out.println("---------------------------------GET CLIENT CHARGE---------------------------------------------"); - final String CHARGES_URL = "/mifosng-provider/api/v1/clients/" + clientId + "/charges?paid=false&" + Utils.TENANT_IDENTIFIER; - ArrayList list = Utils.performServerGet(requestSpec, responseSpec, CHARGES_URL, "amountOutstanding"); - return list != null && !list.isEmpty() ? list.get(0) : null; + final String CHARGES_URL = "/mifosng-provider/api/v1/clients/" + clientId + "/charges/" + clientChargeId + "?" + + Utils.TENANT_IDENTIFIER; + return Utils.performServerGet(requestSpec, responseSpec, CHARGES_URL, "amountOutstanding"); } public static Boolean getClientTransactions(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/SearchParameters.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/SearchParameters.java index 25586a450..3e4375db7 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/SearchParameters.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/SearchParameters.java @@ -120,6 +120,20 @@ public final class SearchParameters { loanId, savingsId, orphansOnly); } + public static SearchParameters forPagination(final Integer offset, final Integer limit) { + + final Integer maxLimitAllowed = getCheckedLimit(limit); + final Long staffId = null; + final Long loanId = null; + final Long savingsId = null; + final Boolean orphansOnly = false; + final String orderBy = null; + final String sortOrder = null; + + return new SearchParameters(null, null, null, null, null, null, null, offset, maxLimitAllowed, orderBy, sortOrder, staffId, null, + loanId, savingsId, orphansOnly); + } + public static SearchParameters forSavings(final String sqlSearch, final String externalId, final Integer offset, final Integer limit, final String orderBy, final String sortOrder) { @@ -171,10 +185,10 @@ public final class SearchParameters { this.currencyCode = null; } - public SearchParameters(final String sqlSearch, final Long officeId, final String externalId, final String name, - final String hierarchy, final String firstname, final String lastname, final Integer offset, final Integer limit, - final String orderBy, final String sortOrder, final Long staffId, final String accountNo, final Long loanId, - final Long savingsId, final Boolean orphansOnly, final String currencyCode) { + public SearchParameters(final String sqlSearch, final Long officeId, final String externalId, final String name, final String hierarchy, + final String firstname, final String lastname, final Integer offset, final Integer limit, final String orderBy, + final String sortOrder, final Long staffId, final String accountNo, final Long loanId, final Long savingsId, + final Boolean orphansOnly, final String currencyCode) { this.sqlSearch = sqlSearch; this.officeId = officeId; this.externalId = externalId; @@ -245,11 +259,11 @@ public final class SearchParameters { public Long getOfficeId() { return this.officeId; } - - public String getCurrencyCode(){ + + public String getCurrencyCode() { return this.currencyCode; } - + public String getExternalId() { return this.externalId; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientChargesApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientChargesApiResource.java index 98b77b59e..45d1dca83 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientChargesApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientChargesApiResource.java @@ -33,6 +33,7 @@ import org.mifosplatform.infrastructure.core.exception.UnrecognizedQueryParamExc import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer; import org.mifosplatform.infrastructure.core.service.Page; +import org.mifosplatform.infrastructure.core.service.SearchParameters; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.portfolio.charge.data.ChargeData; import org.mifosplatform.portfolio.charge.service.ChargeReadPlatformService; @@ -89,9 +90,10 @@ public class ClientChargesApiResource { new Object[] { ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_ALL, ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_ACTIVE, ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_INACTIVE }); } + final SearchParameters searchParameters = SearchParameters.forPagination(offset, limit); final Page clientCharges = this.clientChargeReadPlatformService.retrieveClientCharges(clientId, chargeStatus, - pendingPayment, limit, offset); + pendingPayment, searchParameters); return this.toApiJsonSerializer.serialize(settings, clientCharges, ClientApiConstants.CLIENT_CHARGES_RESPONSE_DATA_PARAMETERS); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientTransactionsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientTransactionsApiResource.java index 949e2d0e9..05ad6304e 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientTransactionsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientTransactionsApiResource.java @@ -26,6 +26,7 @@ import org.mifosplatform.infrastructure.core.exception.UnrecognizedQueryParamExc import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer; import org.mifosplatform.infrastructure.core.service.Page; +import org.mifosplatform.infrastructure.core.service.SearchParameters; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.portfolio.client.data.ClientTransactionData; import org.mifosplatform.portfolio.client.service.ClientTransactionReadPlatformService; @@ -61,8 +62,10 @@ public class ClientTransactionsApiResource { public String retrieveAllClientTransactions(@PathParam("clientId") final Long clientId, @Context final UriInfo uriInfo, @QueryParam("offset") final Integer offset, @QueryParam("limit") final Integer limit) { this.context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_CHARGES_RESOURCE_NAME); + + SearchParameters searchParameters = SearchParameters.forPagination(offset, limit); final Page clientTransactions = this.clientTransactionReadPlatformService.retrieveAllTransactions(clientId, - limit, offset); + searchParameters); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); return this.toApiJsonSerializer.serialize(settings, clientTransactions, diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientRepositoryWrapper.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientRepositoryWrapper.java index 9ca9acbd1..f3c57127d 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientRepositoryWrapper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientRepositoryWrapper.java @@ -5,6 +5,7 @@ */ package org.mifosplatform.portfolio.client.domain; +import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.portfolio.client.exception.ClientNotActiveException; import org.mifosplatform.portfolio.client.exception.ClientNotFoundException; import org.springframework.beans.factory.annotation.Autowired; @@ -20,10 +21,12 @@ import org.springframework.stereotype.Service; public class ClientRepositoryWrapper { private final ClientRepository repository; + private final PlatformSecurityContext context; @Autowired - public ClientRepositoryWrapper(final ClientRepository repository) { + public ClientRepositoryWrapper(final ClientRepository repository, final PlatformSecurityContext context) { this.repository = repository; + this.context = context; } public Client findOneWithNotFoundDetection(final Long id) { @@ -44,9 +47,11 @@ public class ClientRepositoryWrapper { this.repository.delete(client); } - public Client getActiveClient(Long clientId) { + public Client getActiveClientInUserScope(Long clientId) { final Client client = this.findOneWithNotFoundDetection(clientId); if (client.isNotActive()) { throw new ClientNotActiveException(client.getId()); } + this.context.validateAccessRights(client.getOffice().getHierarchy()); return client; } + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeReadPlatformService.java index 197661d47..ba28d8521 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeReadPlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeReadPlatformService.java @@ -6,12 +6,12 @@ package org.mifosplatform.portfolio.client.service; import org.mifosplatform.infrastructure.core.service.Page; +import org.mifosplatform.infrastructure.core.service.SearchParameters; import org.mifosplatform.portfolio.client.data.ClientChargeData; public interface ClientChargeReadPlatformService { - - Page retrieveClientCharges(Long clientId, String status, Boolean isPaid, Integer limit, Integer offset); + Page retrieveClientCharges(Long clientId, String status, Boolean pendingPayment, SearchParameters parameters); ClientChargeData retrieveClientCharge(Long clientId, Long clientChargeId); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeReadPlatformServiceImpl.java index 8a6f6a90b..d08e1da61 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeReadPlatformServiceImpl.java @@ -16,6 +16,7 @@ import org.mifosplatform.infrastructure.core.domain.JdbcSupport; import org.mifosplatform.infrastructure.core.service.Page; import org.mifosplatform.infrastructure.core.service.PaginationHelper; import org.mifosplatform.infrastructure.core.service.RoutingDataSource; +import org.mifosplatform.infrastructure.core.service.SearchParameters; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.organisation.monetary.data.CurrencyData; import org.mifosplatform.portfolio.charge.data.ChargeData; @@ -118,8 +119,8 @@ public class ClientChargeReadPlatformServiceImpl implements ClientChargeReadPlat } @Override - public Page retrieveClientCharges(Long clientId, String status, Boolean pendingPayment, Integer limit, - Integer offset) { + public Page retrieveClientCharges(Long clientId, String status, Boolean pendingPayment, + SearchParameters searchParameters) { final ClientChargeMapper rm = new ClientChargeMapper(); final StringBuilder sqlBuilder = new StringBuilder(); sqlBuilder.append("select SQL_CALC_FOUND_ROWS ").append(rm.schema()).append(" where cc.client_id=? "); @@ -133,13 +134,21 @@ public class ClientChargeReadPlatformServiceImpl implements ClientChargeReadPlat // filter for paid charges if (pendingPayment != null && pendingPayment) { - sqlBuilder.append(" and ( cc.is_paid_derived = 0 and cc.waived = 1) "); + sqlBuilder.append(" and ( cc.is_paid_derived = 0 and cc.waived = 0) "); } else if (pendingPayment != null && !pendingPayment) { - sqlBuilder.append(" and (cc.is_paid_derived = 1 or cc.waived = 0) "); + sqlBuilder.append(" and (cc.is_paid_derived = 1 or cc.waived = 1) "); + } + + sqlBuilder.append(" order by cc.charge_time_enum ASC, cc.charge_due_date DESC, cc.is_penalty ASC "); + + // apply limit and offsets + if (searchParameters.isLimited()) { + sqlBuilder.append(" limit ").append(searchParameters.getLimit()); + if (searchParameters.isOffset()) { + sqlBuilder.append(" offset ").append(searchParameters.getOffset()); + } } - sqlBuilder.append( - " order by cc.charge_time_enum ASC, cc.charge_due_date DESC, cc.is_penalty ASC " + "limit " + limit + " offset " + offset); final String sqlCountRows = "SELECT FOUND_ROWS()"; return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), new Object[] { clientId }, this.clientChargeMapper); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeWritePlatformServiceJpaRepositoryImpl.java index 901bb2b09..6c5a05632 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeWritePlatformServiceJpaRepositoryImpl.java @@ -23,6 +23,7 @@ import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder; import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; +import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException; import org.mifosplatform.infrastructure.core.service.DateUtils; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.organisation.holiday.domain.HolidayRepositoryWrapper; @@ -43,12 +44,17 @@ import org.mifosplatform.portfolio.client.domain.ClientTransactionRepository; import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail; import org.mifosplatform.portfolio.paymentdetail.service.PaymentDetailWritePlatformService; import org.mifosplatform.useradministration.domain.AppUser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataIntegrityViolationException; import org.springframework.stereotype.Service; @Service public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements ClientChargeWritePlatformService { + private final static Logger logger = LoggerFactory.getLogger(ClientChargeWritePlatformServiceJpaRepositoryImpl.class); + private final PlatformSecurityContext context; private final ChargeRepositoryWrapper chargeRepository; private final ClientRepositoryWrapper clientRepository; @@ -84,74 +90,83 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client @Override public CommandProcessingResult addCharge(Long clientId, JsonCommand command) { + try { + this.clientChargeDataValidator.validateAdd(command.json()); - this.clientChargeDataValidator.validateAdd(command.json()); + final Client client = clientRepository.getActiveClientInUserScope(clientId); - final Client client = clientRepository.getActiveClient(clientId); + final Long chargeDefinitionId = command.longValueOfParameterNamed(ClientApiConstants.chargeIdParamName); + final Charge charge = this.chargeRepository.findOneWithNotFoundDetection(chargeDefinitionId); - final Long chargeDefinitionId = command.longValueOfParameterNamed(ClientApiConstants.chargeIdParamName); - final Charge charge = this.chargeRepository.findOneWithNotFoundDetection(chargeDefinitionId); + // validate for client charge + if (!charge.isClientCharge()) { + final String errorMessage = "Charge with identifier " + charge.getId() + " cannot be applied to a Client"; + throw new ChargeCannotBeAppliedToException("client", errorMessage, charge.getId()); + } - // validate for client charge - if (!charge.isClientCharge()) { - final String errorMessage = "Charge with identifier " + charge.getId() + " cannot be applied to a Client"; - throw new ChargeCannotBeAppliedToException("client", errorMessage, charge.getId()); + final ClientCharge clientCharge = ClientCharge.createNew(client, charge, command); + + final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()); + validateDueDateOnWorkingDay(clientCharge, fmt); + + this.clientChargeRepository.save(clientCharge); + + return new CommandProcessingResultBuilder() // + .withEntityId(clientCharge.getId()) // + .withOfficeId(clientCharge.getClient().getOffice().getId()) // + .withClientId(clientCharge.getClient().getId()) // + .build(); + } catch (DataIntegrityViolationException dve) { + handleDataIntegrityIssues(clientId, null, dve); + return CommandProcessingResult.empty(); } - - final ClientCharge clientCharge = ClientCharge.createNew(client, charge, command); - - final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()); - validateDueDateOnWorkingDay(clientCharge, fmt); - - this.clientChargeRepository.save(clientCharge); - - return new CommandProcessingResultBuilder() // - .withEntityId(clientCharge.getId()) // - .withOfficeId(clientCharge.getClient().getOffice().getId()) // - .withClientId(clientCharge.getClient().getId()) // - .build(); } @Override public CommandProcessingResult payCharge(Long clientId, Long clientChargeId, JsonCommand command) { - this.clientChargeDataValidator.validatePayCharge(command.json()); + try { + this.clientChargeDataValidator.validatePayCharge(command.json()); - final Client client = this.clientRepository.getActiveClient(clientId); + final Client client = this.clientRepository.getActiveClientInUserScope(clientId); - final ClientCharge clientCharge = this.clientChargeRepository.findOneWithNotFoundDetection(clientChargeId); + final ClientCharge clientCharge = this.clientChargeRepository.findOneWithNotFoundDetection(clientChargeId); - final Locale locale = command.extractLocale(); - final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale); - final LocalDate transactionDate = command.localDateValueOfParameterNamed(ClientApiConstants.transactionDateParamName); - final BigDecimal amountPaid = command.bigDecimalValueOfParameterNamed(ClientApiConstants.amountParamName); - final Money chargePaid = Money.of(clientCharge.getCurrency(), amountPaid); + final Locale locale = command.extractLocale(); + final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale); + final LocalDate transactionDate = command.localDateValueOfParameterNamed(ClientApiConstants.transactionDateParamName); + final BigDecimal amountPaid = command.bigDecimalValueOfParameterNamed(ClientApiConstants.amountParamName); + final Money chargePaid = Money.of(clientCharge.getCurrency(), amountPaid); - // Validate business rules for payment - validatePaymentTransaction(client, clientCharge, fmt, transactionDate, amountPaid); + // Validate business rules for payment + validatePaymentTransaction(client, clientCharge, fmt, transactionDate, amountPaid); - // pay the charge - clientCharge.pay(chargePaid); + // pay the charge + clientCharge.pay(chargePaid); - // create Payment Transaction - final Map changes = new LinkedHashMap<>(); - final PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes); + // create Payment Transaction + final Map changes = new LinkedHashMap<>(); + final PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes); - ClientTransaction clientTransaction = ClientTransaction.payCharge(client, client.getOffice(), paymentDetail, transactionDate, - chargePaid, clientCharge.getCurrency().getCode(), getAppUserIfPresent()); - this.clientTransactionRepository.saveAndFlush(clientTransaction); + ClientTransaction clientTransaction = ClientTransaction.payCharge(client, client.getOffice(), paymentDetail, transactionDate, + chargePaid, clientCharge.getCurrency().getCode(), getAppUserIfPresent()); + this.clientTransactionRepository.saveAndFlush(clientTransaction); - // update charge paid by associations - final ClientChargePaidBy chargePaidBy = ClientChargePaidBy.instance(clientTransaction, clientCharge, amountPaid); - clientTransaction.getClientChargePaidByCollection().add(chargePaidBy); + // update charge paid by associations + final ClientChargePaidBy chargePaidBy = ClientChargePaidBy.instance(clientTransaction, clientCharge, amountPaid); + clientTransaction.getClientChargePaidByCollection().add(chargePaidBy); - // generate accounting entries - generateAccountingEntries(clientTransaction); + // generate accounting entries + generateAccountingEntries(clientTransaction); - return new CommandProcessingResultBuilder() // - .withTransactionId(clientTransaction.getId().toString())// - .withEntityId(clientCharge.getId()) // - .withOfficeId(clientCharge.getClient().getOffice().getId()) // - .withClientId(clientCharge.getClient().getId()).build(); + return new CommandProcessingResultBuilder() // + .withTransactionId(clientTransaction.getId().toString())// + .withEntityId(clientCharge.getId()) // + .withOfficeId(clientCharge.getClient().getOffice().getId()) // + .withClientId(clientCharge.getClient().getId()).build(); + } catch (DataIntegrityViolationException dve) { + handleDataIntegrityIssues(clientId, clientChargeId, dve); + return CommandProcessingResult.empty(); + } } @@ -162,54 +177,65 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client @Override public CommandProcessingResult waiveCharge(Long clientId, Long clientChargeId) { - final Client client = this.clientRepository.getActiveClient(clientId); - final ClientCharge clientCharge = this.clientChargeRepository.findOneWithNotFoundDetection(clientChargeId); - final LocalDate transactionDate = DateUtils.getLocalDateOfTenant(); + try { + final Client client = this.clientRepository.getActiveClientInUserScope(clientId); + final ClientCharge clientCharge = this.clientChargeRepository.findOneWithNotFoundDetection(clientChargeId); + final LocalDate transactionDate = DateUtils.getLocalDateOfTenant(); - // Validate business rules for payment - validateWaiverTransaction(client, clientCharge); + // Validate business rules for payment + validateWaiverTransaction(client, clientCharge); - // waive the charge - Money waivedAmount = clientCharge.waive(); + // waive the charge + Money waivedAmount = clientCharge.waive(); - // create Waiver Transaction - ClientTransaction clientTransaction = ClientTransaction.waiver(client, client.getOffice(), transactionDate, waivedAmount, - clientCharge.getCurrency().getCode(), getAppUserIfPresent()); - this.clientTransactionRepository.save(clientTransaction); + // create Waiver Transaction + ClientTransaction clientTransaction = ClientTransaction.waiver(client, client.getOffice(), transactionDate, waivedAmount, + clientCharge.getCurrency().getCode(), getAppUserIfPresent()); + this.clientTransactionRepository.save(clientTransaction); - // update charge paid by associations - final ClientChargePaidBy chargePaidBy = ClientChargePaidBy.instance(clientTransaction, clientCharge, waivedAmount.getAmount()); - clientTransaction.getClientChargePaidByCollection().add(chargePaidBy); + // update charge paid by associations + final ClientChargePaidBy chargePaidBy = ClientChargePaidBy.instance(clientTransaction, clientCharge, waivedAmount.getAmount()); + clientTransaction.getClientChargePaidByCollection().add(chargePaidBy); - return new CommandProcessingResultBuilder().withTransactionId(clientTransaction.getId().toString())// - .withEntityId(clientCharge.getId()) // - .withOfficeId(clientCharge.getClient().getOffice().getId()) // - .withClientId(clientCharge.getClient().getId()) // - .build(); + return new CommandProcessingResultBuilder().withTransactionId(clientTransaction.getId().toString())// + .withEntityId(clientCharge.getId()) // + .withOfficeId(clientCharge.getClient().getOffice().getId()) // + .withClientId(clientCharge.getClient().getId()) // + .build(); + } catch (DataIntegrityViolationException dve) { + handleDataIntegrityIssues(clientId, clientChargeId, dve); + return CommandProcessingResult.empty(); + } } @Override public CommandProcessingResult deleteCharge(Long clientId, Long clientChargeId) { - final Client client = this.clientRepository.getActiveClient(clientId); - final ClientCharge clientCharge = this.clientChargeRepository.findOneWithNotFoundDetection(clientChargeId); + try { + final Client client = this.clientRepository.getActiveClientInUserScope(clientId); + final ClientCharge clientCharge = this.clientChargeRepository.findOneWithNotFoundDetection(clientChargeId); - // Validate business rules for charge deletion - validateChargeDeletion(client, clientCharge); + // Validate business rules for charge deletion + validateChargeDeletion(client, clientCharge); - // delete the charge - clientChargeRepository.delete(clientCharge); + // delete the charge + clientChargeRepository.delete(clientCharge); - return new CommandProcessingResultBuilder() // - .withEntityId(clientCharge.getId()) // - .withOfficeId(clientCharge.getClient().getOffice().getId()) // - .withClientId(clientCharge.getClient().getId()) // - .build(); + return new CommandProcessingResultBuilder() // + .withEntityId(clientCharge.getId()) // + .withOfficeId(clientCharge.getClient().getOffice().getId()) // + .withClientId(clientCharge.getClient().getId()) // + .build(); + } catch (DataIntegrityViolationException dve) { + handleDataIntegrityIssues(clientId, clientChargeId, dve); + return CommandProcessingResult.empty(); + } } /** * Validates transaction to ensure that
* charge is active
- * transaction date is valid (between client activation and todays date)
+ * transaction date is valid (between client activation and todays date) + *
* charge is not already paid or waived
* amount is not more than total due * @@ -304,14 +330,16 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client * @return */ @Override - public CommandProcessingResult updateCharge(Long clientId, JsonCommand command) { - // this.clientChargeDataValidator.validateAdd(command.json()); + public CommandProcessingResult updateCharge(@SuppressWarnings("unused") Long clientId, + @SuppressWarnings("unused") JsonCommand command) { + // functionality not yet supported return null; } @Override + @SuppressWarnings("unused") public CommandProcessingResult inactivateCharge(Long clientId, Long clientChargeId) { - // TODO Auto-generated method stub + // functionality not yet supported return null; } @@ -378,4 +406,19 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client return user; } + private void handleDataIntegrityIssues(@SuppressWarnings("unused") final Long clientId, final Long clientChargeId, + final DataIntegrityViolationException dve) { + + final Throwable realCause = dve.getMostSpecificCause(); + if (realCause.getMessage().contains("FK_m_client_charge_paid_by_m_client_charge")) { + + throw new PlatformDataIntegrityException("error.msg.client.charge.cannot.be.deleted", + "Client charge with id `" + clientChargeId + "` cannot be deleted as transactions have been made on the same", + "clientChargeId", clientChargeId); } + + logger.error(dve.getMessage(), dve); + throw new PlatformDataIntegrityException("error.msg.client.charges.unknown.data.integrity.issue", + "Unknown data integrity issue with resource."); + } + } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientTransactionReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientTransactionReadPlatformService.java index dd68fd3fd..73320f110 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientTransactionReadPlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientTransactionReadPlatformService.java @@ -8,13 +8,14 @@ package org.mifosplatform.portfolio.client.service; import java.util.Collection; import org.mifosplatform.infrastructure.core.service.Page; +import org.mifosplatform.infrastructure.core.service.SearchParameters; import org.mifosplatform.portfolio.client.data.ClientTransactionData; import org.springframework.transaction.annotation.Transactional; public interface ClientTransactionReadPlatformService { @Transactional(readOnly = true) - public Page retrieveAllTransactions(Long clientId, Integer limit, Integer offset); + public Page retrieveAllTransactions(Long clientId, SearchParameters parameters); @Transactional(readOnly = true) public Collection retrieveAllTransactions(final Long clientId, final Long chargeId); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientTransactionReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientTransactionReadPlatformServiceImpl.java index 22266bff5..329fd4214 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientTransactionReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientTransactionReadPlatformServiceImpl.java @@ -16,6 +16,7 @@ import org.mifosplatform.infrastructure.core.domain.JdbcSupport; import org.mifosplatform.infrastructure.core.service.Page; import org.mifosplatform.infrastructure.core.service.PaginationHelper; import org.mifosplatform.infrastructure.core.service.RoutingDataSource; +import org.mifosplatform.infrastructure.core.service.SearchParameters; import org.mifosplatform.organisation.monetary.data.CurrencyData; import org.mifosplatform.portfolio.client.data.ClientTransactionData; import org.mifosplatform.portfolio.client.domain.ClientEnumerations; @@ -121,13 +122,24 @@ public class ClientTransactionReadPlatformServiceImpl implements ClientTransacti } @Override - public Page retrieveAllTransactions(Long clientId, Integer limit, Integer offset) { + public Page retrieveAllTransactions(Long clientId, SearchParameters searchParameters) { Object[] parameters = new Object[1]; - String sql = "select SQL_CALC_FOUND_ROWS " + this.clientTransactionMapper.schema() + " where c.id = ? "; + final StringBuilder sqlBuilder = new StringBuilder(); + sqlBuilder.append("select SQL_CALC_FOUND_ROWS ").append(this.clientTransactionMapper.schema()).append(" where c.id = ? "); parameters[0] = clientId; final String sqlCountRows = "SELECT FOUND_ROWS()"; - sql = sql + " order by tr.transaction_date DESC, tr.created_date DESC, tr.id DESC limit " + limit + " offset " + offset; - return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sql, parameters, this.clientTransactionMapper); + sqlBuilder.append(" order by tr.transaction_date DESC, tr.created_date DESC, tr.id DESC "); + + // apply limit and offsets + if (searchParameters.isLimited()) { + sqlBuilder.append(" limit ").append(searchParameters.getLimit()); + if (searchParameters.isOffset()) { + sqlBuilder.append(" offset ").append(searchParameters.getOffset()); + } + } + + return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), parameters, + this.clientTransactionMapper); } @Override diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientTransactionWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientTransactionWritePlatformServiceJpaRepositoryImpl.java index e49530a62..d93b54ef5 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientTransactionWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientTransactionWritePlatformServiceJpaRepositoryImpl.java @@ -45,7 +45,7 @@ public class ClientTransactionWritePlatformServiceJpaRepositoryImpl implements C @Override public CommandProcessingResult undo(Long clientId, Long transactionId) { - final Client client = this.clientRepository.getActiveClient(clientId); + final Client client = this.clientRepository.getActiveClientInUserScope(clientId); final ClientTransaction clientTransaction = this.clientTransactionRepository.findOneWithNotFoundDetection(clientId, transactionId); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/DisbursementData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/DisbursementData.java index 943e15562..b65afef6f 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/DisbursementData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/DisbursementData.java @@ -19,6 +19,7 @@ public class DisbursementData implements Comparable { private final LocalDate expectedDisbursementDate; private final LocalDate actualDisbursementDate; private final BigDecimal principal; + @SuppressWarnings("unused") private final String loanChargeId; private final BigDecimal chargeAmount; @@ -43,11 +44,11 @@ public class DisbursementData implements Comparable { public BigDecimal amount() { return this.principal; } - - public BigDecimal getChargeAmount(){ - return this.chargeAmount; + + public BigDecimal getChargeAmount() { + return this.chargeAmount; } - + public boolean isDisbursed() { return this.actualDisbursementDate != null; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java index 5ee801fb2..fabb39e56 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java @@ -373,6 +373,7 @@ public class SavingsAccount extends AbstractPersistable { this.summary = new SavingsAccountSummary(); this.allowOverdraft = allowOverdraft; this.overdraftLimit = overdraftLimit; + esnureOverdraftLimitsSetForOverdraftAccounts(); this.enforceMinRequiredBalance = enforceMinRequiredBalance; this.minRequiredBalance = minRequiredBalance; @@ -1110,7 +1111,20 @@ public class SavingsAccount extends AbstractPersistable { } validateLockinDetails(baseDataValidator); + esnureOverdraftLimitsSetForOverdraftAccounts(); } + + /** + * If overdrafts are allowed and the overdraft limit is not set, set the + * same to Zero + **/ + private void esnureOverdraftLimitsSetForOverdraftAccounts() { + + if (this.allowOverdraft && this.overdraftLimit == null) { + this.overdraftLimit = BigDecimal.ZERO; + } + } + private void validateLockinDetails(final DataValidatorBuilder baseDataValidator) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsProduct.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsProduct.java index 1bd57c058..5dac8b733 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsProduct.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsProduct.java @@ -141,7 +141,7 @@ public class SavingsProduct extends AbstractPersistable { protected boolean withdrawalFeeApplicableForTransfer; @ManyToMany - @JoinTable(name = "m_savings_product_charge", joinColumns = @JoinColumn(name = "savings_product_id"), inverseJoinColumns = @JoinColumn(name = "charge_id")) + @JoinTable(name = "m_savings_product_charge", joinColumns = @JoinColumn(name = "savings_product_id") , inverseJoinColumns = @JoinColumn(name = "charge_id") ) protected Set charges; @Column(name = "allow_overdraft") @@ -236,11 +236,24 @@ public class SavingsProduct extends AbstractPersistable { this.allowOverdraft = allowOverdraft; this.overdraftLimit = overdraftLimit; + esnureOverdraftLimitsSetForOverdraftAccounts(); + this.enforceMinRequiredBalance = enforceMinRequiredBalance; this.minRequiredBalance = minRequiredBalance; this.minBalanceForInterestCalculation = minBalanceForInterestCalculation; } + /** + * If overdrafts are allowed and the overdraft limit is not set, set the + * same to Zero + **/ + private void esnureOverdraftLimitsSetForOverdraftAccounts() { + + if (this.allowOverdraft && this.overdraftLimit() == null) { + this.overdraftLimit = BigDecimal.ZERO; + } + } + public MonetaryCurrency currency() { return this.currency.copy(); } @@ -448,6 +461,7 @@ public class SavingsProduct extends AbstractPersistable { } validateLockinDetails(); + esnureOverdraftLimitsSetForOverdraftAccounts(); return actualChanges; }