From 6d79d59b745c2622dcc7a2d4d335691c818e8f48 Mon Sep 17 00:00:00 2001 From: Pramod Nuthakki Date: Tue, 9 Dec 2014 09:46:25 +0530 Subject: [PATCH] MIFOSX-1709 : added test cases and api documentation --- api-docs/apiLive.htm | 128 +++- .../ClientLoanIntegrationTest.java | 49 +- .../LoanApplicationApprovalTest.java | 2 +- .../common/loans/LoanProductTestBuilder.java | 22 + .../common/loans/LoanTransactionHelper.java | 93 ++- .../common/savings/SavingsAccountHelper.java | 73 ++- .../guarantor/GuarantorHelper.java | 59 ++ .../loanaccount/guarantor/GuarantorTest.java | 607 ++++++++++++++++++ .../guarantor/GuarantorTestBuilder.java | 74 +++ .../common/service/BusinessEventListner.java | 12 + .../service/BusinessEventNotifierService.java | 21 + .../BusinessEventNotifierServiceImpl.java | 40 ++ .../service/GuarantorDomainServiceImpl.java | 44 ++ ...ritePlatformServiceJpaRepositoryIImpl.java | 25 +- 14 files changed, 1148 insertions(+), 101 deletions(-) create mode 100755 mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/loanaccount/guarantor/GuarantorHelper.java create mode 100755 mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/loanaccount/guarantor/GuarantorTest.java create mode 100755 mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/loanaccount/guarantor/GuarantorTestBuilder.java diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm index 8600adf2d..6329165db 100644 --- a/api-docs/apiLive.htm +++ b/api-docs/apiLive.htm @@ -997,6 +997,14 @@ + + + loans/{loanId}?command=recoverGuarantees + Recover From Guarantors + + + + Loan Transactions loans/{loanId}/transactions?command=repayment @@ -7383,6 +7391,11 @@ GET https://DomainName/api/v1/loans/template?templateType=individual&clientId=1& optional, Either 'all' or a comma separated list of loan 'associations' (itemised below). +
exclude
+
+ optional, 'all' and a comma separated list of + loan associations (itemised below) as 'exclude'. +

Associations are just extra pieces of data that you might or might not want to retrieve.
@@ -7422,6 +7435,8 @@ GET https://DomainName/api/v1/loans/template?templateType=individual&clientId=1&
loans/1?associations=all

+
loans/1?associations=all&exclude=guarantors
+

loans/1?fields=id,principal,annualInterestRate&associations=repaymentSchedule,transactions
@@ -8239,6 +8254,30 @@ Request Body: + +   +
+
+

Recover Loan Guarantee

+
+
+ +POST https://DomainName/api/v1/loans/{loanId}?command=recoverGuarantees + + +POST loans/1?command=approve +Content-Type: application/json +No Request Body: + + +{ + + "loanId": 1 +} + +
+
+  
@@ -9144,6 +9183,20 @@ Request Body: birth details of an external guarantor + + savingsId + + + Guarantors Savings Account on which Amount will be blocked + + + + amount + + + Guarantee amount which will be blocked on savings account. + +
@@ -9203,6 +9256,7 @@ GET https://DomainName/api/v1/loans/{loanId}/guarantors

Example Request:

loans/1/guarantors/template
+
loans/1/guarantors/accounts/template?clientId=1
@@ -9232,6 +9286,39 @@ GET https://DomainName/api/v1/loans/{loanId}/guarantors/template "value": "EXTERNAL" } ] +} + + +GET https://DomainName/api/v1/loans/{loanId}/guarantors/accounts/template?clientId={clientId} + + +{ + "guarantorType": { + "id": 1, + "code": "guarantor.existing.customer", + "value": "CUSTOMER" + }, + "status": false, + "accountLinkingOptions": [ + { + "id": 1, + "accountNo": "000000001", + "clientId": 3, + "clientName": "Client_FirstName_UUV18 Client_LastName_9T2D", + "productId": 1, + "productName": "FIXED_DEPOSIT_PRODUCT_U0NS9T", + "fieldOfficerId": 0, + "currency": { + "code": "USD", + "name": "US Dollar", + "decimalPlaces": 4, + "inMultiplesOf": 100, + "displaySymbol": "$", + "nameCode": "currency.USD", + "displayLabel": "US Dollar ($)" + } + } + ] }
@@ -9299,6 +9386,15 @@ GET https://DomainName/api/v1/loans/{loanId}/guarantors/{guarantorId} guarantorTypeId, firstname, lastname + + + + + + + +
Optional Fields + for "internal" guarantors
savingsId, amount
@@ -9382,9 +9478,12 @@ Request Body:
DELETE https://DomainName/api/v1/loans/{loanId}/guarantors/{guarantorId} +DELETE https://DomainName/api/v1/loans/{loanId}/guarantors/{guarantorId}?guarantorFundingId={guarantorFundingId} + DELETE loans/1/guarantors/1 +DELETE loans/1/guarantors/1?guarantorFundingId=1 Content-Type: application/json No Request Body: @@ -12282,7 +12381,7 @@ GET https://DomainName/api/v1/loanproducts/{productId} numberOfRepaymentVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle, multiDisburseLoan,maxTrancheCount, - outstandingLoanBalance,overdueDaysForNPA + outstandingLoanBalance,overdueDaysForNPA,holdGuaranteeFunds @@ -12323,6 +12422,22 @@ GET https://DomainName/api/v1/loanproducts/{productId} recalculationRestFrequencyInterval, recalculationRestFrequencyDate + + + + + + + +
Additional Mandatory Fields if Hold Guarantee funds is enabled(true)
mandatoryGuarantee
+ + + + + + + +
Additional Optional Fields if Hold Guarantee funds is enabled(true)
minimumGuaranteeFromOwnFunds,minimumGuaranteeFromGuarantor
@@ -12385,7 +12500,8 @@ Request Body: "overpaymentLiabilityAccountId":11, "daysInMonthType":1, "daysInYearType":1, -"isInterestRecalculationEnabled":"false" +"isInterestRecalculationEnabled":"false", +"holdGuaranteeFunds":"false" } @@ -33482,6 +33598,14 @@ No Request Body: + + + loans/{loanId}?command=recoverGuarantees + Recover From Guarantors + + + + loans/{loanId}/transactions/template diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ClientLoanIntegrationTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ClientLoanIntegrationTest.java index bf2750e8c..98126146c 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ClientLoanIntegrationTest.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ClientLoanIntegrationTest.java @@ -36,8 +36,6 @@ import org.mifosplatform.integrationtests.common.loans.LoanProductTestBuilder; import org.mifosplatform.integrationtests.common.loans.LoanStatusChecker; import org.mifosplatform.integrationtests.common.loans.LoanTransactionHelper; import org.mifosplatform.integrationtests.common.savings.SavingsAccountHelper; -import org.mifosplatform.integrationtests.common.savings.SavingsProductHelper; -import org.mifosplatform.integrationtests.common.savings.SavingsStatusChecker; import com.jayway.restassured.builder.RequestSpecBuilder; import com.jayway.restassured.builder.ResponseSpecBuilder; @@ -87,7 +85,8 @@ public class ClientLoanIntegrationTest { ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID); final Integer loanProductID = createLoanProduct(false, NONE); final Integer loanID = applyForLoanApplication(clientID, loanProductID, null, null, "12,000.00"); - final ArrayList loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec,loanID); + final ArrayList loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, + loanID); verifyLoanRepaymentSchedule(loanSchedule); } @@ -324,7 +323,8 @@ public class ClientLoanIntegrationTest { validateCharge(flat, loanCharges, "150.0", "150.0", "0.0", "0.0"); validateNumberForEqual("654.24", String.valueOf(firstInstallment.get("feeChargesDue"))); - final Integer savingsId = createSavings(clientID); + final Integer savingsId = SavingsAccountHelper.openSavingsAccount(this.requestSpec, this.responseSpec, clientID, + MINIMUM_OPENING_BALANCE); this.loanTransactionHelper.updateLoan(loanID, updateLoanJson(clientID, loanProductID, copyChargesForUpdate(loanCharges, null, null), String.valueOf(savingsId))); @@ -527,7 +527,8 @@ public class ClientLoanIntegrationTest { "0.0"); validateChargeExcludePrecission(flat, loanCharges, "100.0", "400", "0.0", "0.0"); - final Integer savingsId = createSavings(clientID); + final Integer savingsId = SavingsAccountHelper.openSavingsAccount(this.requestSpec, this.responseSpec, clientID, + MINIMUM_OPENING_BALANCE); this.loanTransactionHelper.updateLoan(loanID, updateLoanJson(clientID, loanProductID, copyChargesForUpdate(loanCharges, null, null), String.valueOf(savingsId))); @@ -687,7 +688,8 @@ public class ClientLoanIntegrationTest { ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID); final Integer loanProductID = createLoanProduct(false, NONE); - final Integer savingsId = createSavings(clientID); + final Integer savingsId = SavingsAccountHelper.openSavingsAccount(this.requestSpec, this.responseSpec, clientID, + MINIMUM_OPENING_BALANCE); final Integer loanID = applyForLoanApplication(clientID, loanProductID, null, savingsId.toString(), "12,000.00"); Assert.assertNotNull(loanID); @@ -770,7 +772,8 @@ public class ClientLoanIntegrationTest { ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID); final Integer loanProductID = createLoanProduct(true, NONE); - final Integer savingsId = createSavings(clientID); + final Integer savingsId = SavingsAccountHelper.openSavingsAccount(this.requestSpec, this.responseSpec, clientID, + MINIMUM_OPENING_BALANCE); List tranches = new ArrayList<>(); tranches.add(createTrancheDetail("1 March 2014", "25000")); @@ -1158,38 +1161,6 @@ public class ClientLoanIntegrationTest { return map; } - private Integer createSavings(Integer clientID) { - final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE); - Assert.assertNotNull(savingsProductID); - - SavingsAccountHelper savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec); - - final Integer savingsId = savingsAccountHelper.applyForSavingsApplication(clientID, savingsProductID, ACCOUNT_TYPE_INDIVIDUAL); - Assert.assertNotNull(savingsProductID); - - HashMap savingsStatusHashMap = SavingsStatusChecker.getStatusOfSavings(this.requestSpec, this.responseSpec, savingsId); - SavingsStatusChecker.verifySavingsIsPending(savingsStatusHashMap); - - savingsStatusHashMap = savingsAccountHelper.approveSavings(savingsId); - SavingsStatusChecker.verifySavingsIsApproved(savingsStatusHashMap); - - savingsStatusHashMap = savingsAccountHelper.activateSavings(savingsId); - SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap); - return savingsId; - } - - private Integer createSavingsProduct(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, - final String minOpenningBalance) { - System.out.println("------------------------------CREATING NEW SAVINGS PRODUCT ---------------------------------------"); - SavingsProductHelper savingsProductHelper = new SavingsProductHelper(); - final String savingsProductJSON = savingsProductHelper // - .withInterestCompoundingPeriodTypeAsDaily() // - .withInterestPostingPeriodTypeAsMonthly() // - .withInterestCalculationPeriodTypeAsDailyBalance() // - .withMinimumOpenningBalance(minOpenningBalance).build(); - return SavingsProductHelper.createSavingsProduct(savingsProductJSON, requestSpec, responseSpec); - } - private HashMap createTrancheDetail(final String date, final String amount) { HashMap detail = new HashMap(); detail.put("expectedDisbursementDate", date); diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanApplicationApprovalTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanApplicationApprovalTest.java index fbbd84c22..a2f78f53c 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanApplicationApprovalTest.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanApplicationApprovalTest.java @@ -89,7 +89,7 @@ public class LoanApplicationApprovalTest { this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpecForStatusCode403); @SuppressWarnings("unchecked") - List error = (List) this.loanTransactionHelper.approveLoanWithApproveAmount(approveDate, approvalAmount, loanID, + List error = (List) this.loanTransactionHelper.approveLoan(approveDate, approvalAmount, loanID, CommonConstants.RESPONSE_ERROR); assertEquals("error.msg.loan.approval.amount.can't.be.greater.than.loan.amount.demanded", error diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanProductTestBuilder.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanProductTestBuilder.java index 814779437..a83fb9517 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanProductTestBuilder.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanProductTestBuilder.java @@ -88,6 +88,10 @@ public class LoanProductTestBuilder { private String recalculationRestFrequencyInterval = "0"; private String recalculationRestFrequencyDate = null; private String minimumDaysBetweenDisbursalAndFirstRepayment = null; + private Boolean holdGuaranteeFunds = null; + private String mandatoryGuarantee = null; + private String minimumGuaranteeFromOwnFunds = null; + private String minimumGuaranteeFromGuarantor = null; public String build(final String chargeId) { final HashMap map = new HashMap<>(); @@ -145,6 +149,14 @@ public class LoanProductTestBuilder { map.put("recalculationRestFrequencyInterval", recalculationRestFrequencyInterval); map.put("recalculationRestFrequencyDate", recalculationRestFrequencyDate); } + if (holdGuaranteeFunds != null) { + map.put("holdGuaranteeFunds", this.holdGuaranteeFunds); + if (this.holdGuaranteeFunds) { + map.put("mandatoryGuarantee", this.mandatoryGuarantee); + map.put("minimumGuaranteeFromGuarantor", this.minimumGuaranteeFromGuarantor); + map.put("minimumGuaranteeFromOwnFunds", this.minimumGuaranteeFromOwnFunds); + } + } return new Gson().toJson(map); } @@ -385,4 +397,14 @@ public class LoanProductTestBuilder { this.minimumDaysBetweenDisbursalAndFirstRepayment = minimumDaysBetweenDisbursalAndFirstRepayment; return this; } + + public LoanProductTestBuilder withOnHoldFundDetails(final String mandatoryGuarantee, final String minimumGuaranteeFromGuarantor, + final String minimumGuaranteeFromOwnFunds) { + this.holdGuaranteeFunds = true; + this.mandatoryGuarantee = mandatoryGuarantee; + this.minimumGuaranteeFromGuarantor = minimumGuaranteeFromGuarantor; + this.minimumGuaranteeFromOwnFunds = minimumGuaranteeFromOwnFunds; + return this; + } + } diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanTransactionHelper.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanTransactionHelper.java index 2cf84e814..a5a57482d 100755 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanTransactionHelper.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanTransactionHelper.java @@ -35,6 +35,7 @@ public class LoanTransactionHelper { private static final String WAIVE_INTEREST_COMMAND = "waiveinterest"; private static final String MAKE_REPAYMENT_COMMAND = "repayment"; private static final String WITHDRAW_LOAN_APPLICATION_COMMAND = "withdrawnByApplicant"; + private static final String RECOVER_FROM_GUARANTORS_COMMAND = "recoverGuarantees"; public LoanTransactionHelper(final RequestSpecification requestSpec, final ResponseSpecification responseSpec) { this.requestSpec = requestSpec; @@ -48,19 +49,19 @@ public class LoanTransactionHelper { public Integer getLoanId(final String loanApplicationJSON) { return Utils.performServerPost(this.requestSpec, this.responseSpec, APPLY_LOAN_URL, loanApplicationJSON, "loanId"); } + public Integer getLoanOfficerId(final String loanId) { final String GET_LOAN_URL = "/mifosng-provider/api/v1/loans/" + loanId + "?" + Utils.TENANT_IDENTIFIER; return Utils.performServerGet(this.requestSpec, this.responseSpec, GET_LOAN_URL, "loanOfficerId"); } - public Object createLoanAccount(final String loanApplicationJSON, final String responseAttribute) { return Utils.performServerPost(this.requestSpec, this.responseSpec, APPLY_LOAN_URL, loanApplicationJSON, responseAttribute); } public Integer updateLoan(final Integer id, final String loanApplicationJSON) { - return Utils.performServerPut(this.requestSpec, this.responseSpec, "/mifosng-provider/api/v1/loans/" + id - + "?" + Utils.TENANT_IDENTIFIER, loanApplicationJSON, "loanId"); + return Utils.performServerPut(this.requestSpec, this.responseSpec, "/mifosng-provider/api/v1/loans/" + id + "?" + + Utils.TENANT_IDENTIFIER, loanApplicationJSON, "loanId"); } public ArrayList getLoanRepaymentSchedule(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, @@ -69,10 +70,11 @@ public class LoanTransactionHelper { final HashMap response = Utils.performServerGet(requestSpec, responseSpec, URL, "repaymentSchedule"); return (ArrayList) response.get("periods"); } - + public ArrayList getLoanFutureRepaymentSchedule(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, final Integer loanID) { - final String URL = "/mifosng-provider/api/v1/loans/" + loanID + "?associations=repaymentSchedule,futureSchedule&" + Utils.TENANT_IDENTIFIER; + final String URL = "/mifosng-provider/api/v1/loans/" + loanID + "?associations=repaymentSchedule,futureSchedule&" + + Utils.TENANT_IDENTIFIER; final HashMap response = Utils.performServerGet(requestSpec, responseSpec, URL, "repaymentSchedule"); return (ArrayList) response.get("futurePeriods"); } @@ -97,17 +99,17 @@ public class LoanTransactionHelper { public HashMap approveLoan(final String approvalDate, final Integer loanID) { return performLoanTransaction(createLoanOperationURL(APPROVE_LOAN_COMMAND, loanID), getApproveLoanAsJSON(approvalDate)); } - + public HashMap approveLoanWithApproveAmount(final String approvalDate, final String approvalAmount, final Integer loanID) { - return performLoanTransaction(createLoanOperationURL(APPROVE_LOAN_COMMAND, loanID), getApproveLoanAsJSON(approvalDate, approvalAmount)); + return performLoanTransaction(createLoanOperationURL(APPROVE_LOAN_COMMAND, loanID), + getApproveLoanAsJSON(approvalDate, approvalAmount)); } - - public Object approveLoanWithApproveAmount(final String approvalDate, final String approvalAmount, final Integer loanID, - final String responseAttribute) { - + + public Object approveLoan(final String approvalDate, final String approvalAmount, final Integer loanID, final String responseAttribute) { + final String approvalURL = createLoanOperationURL(APPROVE_LOAN_COMMAND, loanID); final String approvalJSONData = getApproveLoanAsJSON(approvalDate, approvalAmount); - + return performLoanTransaction(approvalURL, approvalJSONData, responseAttribute); } @@ -136,6 +138,10 @@ public class LoanTransactionHelper { return performLoanTransaction(createLoanOperationURL(UNDO_DISBURSE_LOAN_COMMAND, loanID), undoDisburseJson); } + public void recoverFromGuarantor(final Integer loanID) { + performLoanTransaction(createLoanOperationURL(RECOVER_FROM_GUARANTORS_COMMAND, loanID), "", ""); + } + public HashMap writeOffLoan(final String date, final Integer loanID) { return performLoanTransaction(createLoanTransactionURL(WRITE_OFF_LOAN_COMMAND, loanID), getWriteOffBodyAsJSON(date)); } @@ -151,8 +157,8 @@ public class LoanTransactionHelper { } public HashMap makeRepayment(final String date, final Float amountToBePaid, final Integer loanID) { - return performLoanTransaction(createLoanTransactionURL(MAKE_REPAYMENT_COMMAND, loanID), - getRepaymentBodyAsJSON(date, amountToBePaid)); + return (HashMap) performLoanTransaction(createLoanTransactionURL(MAKE_REPAYMENT_COMMAND, loanID), + getRepaymentBodyAsJSON(date, amountToBePaid), ""); } public HashMap withdrawLoanApplicationByClient(final String date, final Integer loanID) { @@ -169,32 +175,32 @@ public class LoanTransactionHelper { public Integer updateChargesForLoan(final Integer loanId, final Integer loanchargeId, final String request) { System.out.println("--------------------------------- ADD CHARGES FOR LOAN --------------------------------"); - final String UPDATE_CHARGES_URL = "/mifosng-provider/api/v1/loans/" + loanId + "/charges/" + loanchargeId - + "?" + Utils.TENANT_IDENTIFIER; + final String UPDATE_CHARGES_URL = "/mifosng-provider/api/v1/loans/" + loanId + "/charges/" + loanchargeId + "?" + + Utils.TENANT_IDENTIFIER; final HashMap response = Utils.performServerPut(requestSpec, responseSpec, UPDATE_CHARGES_URL, request, ""); return (Integer) response.get("resourceId"); } public Integer deleteChargesForLoan(final Integer loanId, final Integer loanchargeId) { System.out.println("--------------------------------- DELETE CHARGES FOR LOAN --------------------------------"); - final String DELETE_CHARGES_URL = "/mifosng-provider/api/v1/loans/" + loanId + "/charges/" + loanchargeId - + "?" + Utils.TENANT_IDENTIFIER; + final String DELETE_CHARGES_URL = "/mifosng-provider/api/v1/loans/" + loanId + "/charges/" + loanchargeId + "?" + + Utils.TENANT_IDENTIFIER; final HashMap response = Utils.performServerDelete(requestSpec, responseSpec, DELETE_CHARGES_URL, ""); return (Integer) response.get("resourceId"); } public Integer waiveChargesForLoan(final Integer loanId, final Integer loanchargeId, final String json) { System.out.println("--------------------------------- WAIVE CHARGES FOR LOAN --------------------------------"); - final String CHARGES_URL = "/mifosng-provider/api/v1/loans/" + loanId + "/charges/" + loanchargeId - + "?command=waive&" + Utils.TENANT_IDENTIFIER; + final String CHARGES_URL = "/mifosng-provider/api/v1/loans/" + loanId + "/charges/" + loanchargeId + "?command=waive&" + + Utils.TENANT_IDENTIFIER; final HashMap response = Utils.performServerPost(requestSpec, responseSpec, CHARGES_URL, json, ""); return (Integer) response.get("resourceId"); } public Integer payChargesForLoan(final Integer loanId, final Integer loanchargeId, final String json) { System.out.println("--------------------------------- WAIVE CHARGES FOR LOAN --------------------------------"); - final String CHARGES_URL = "/mifosng-provider/api/v1/loans/" + loanId + "/charges/" + loanchargeId - + "?command=pay&" + Utils.TENANT_IDENTIFIER; + final String CHARGES_URL = "/mifosng-provider/api/v1/loans/" + loanId + "/charges/" + loanchargeId + "?command=pay&" + + Utils.TENANT_IDENTIFIER; final HashMap response = Utils.performServerPost(requestSpec, responseSpec, CHARGES_URL, json, ""); return (Integer) response.get("resourceId"); } @@ -212,19 +218,16 @@ public class LoanTransactionHelper { } private String getApproveLoanAsJSON(final String approvalDate) { - final HashMap map = new HashMap<>(); - map.put("locale", "en"); - map.put("dateFormat", "dd MMMM yyyy"); - map.put("approvedOnDate", approvalDate); - map.put("note", "Approval NOTE"); - return new Gson().toJson(map); + return getApproveLoanAsJSON(approvalDate, null); } - + private String getApproveLoanAsJSON(final String approvalDate, final String approvalAmount) { final HashMap map = new HashMap<>(); map.put("locale", "en"); map.put("dateFormat", "dd MMMM yyyy"); - map.put("approvedLoanAmount", approvalAmount); + if (approvalAmount != null) { + map.put("approvedLoanAmount", approvalAmount); + } map.put("approvedOnDate", approvalDate); map.put("note", "Approval NOTE"); return new Gson().toJson(map); @@ -378,14 +381,36 @@ public class LoanTransactionHelper { "changes"); return (HashMap) response.get("status"); } - + private Object performLoanTransaction(final String postURLForLoanTransaction, final String jsonToBeSent, final String responseAttribute) { return Utils.performServerPost(this.requestSpec, this.responseSpec, postURLForLoanTransaction, jsonToBeSent, responseAttribute); } - - + + public Object adjustLoanTransaction(final Integer loanId, final Integer transactionId, final String date, + final String transactionAmount, final String responseAttribute) { + return adjustLoanTransaction(loanId, transactionId, getAdjustTransactionJSON(date, transactionAmount), responseAttribute); + } + + private Object adjustLoanTransaction(final Integer loanId, final Integer tansactionId, final String jsonToBeSent, + final String responseAttribute) { + final String URL = "/mifosng-provider/api/v1/loans/" + loanId + "/transactions/" + tansactionId + "?" + Utils.TENANT_IDENTIFIER; + return Utils.performServerPost(this.requestSpec, this.responseSpec, URL, jsonToBeSent, responseAttribute); + } + + private String getAdjustTransactionJSON(final String date, final String transactionAmount) { + final HashMap map = new HashMap<>(); + map.put("locale", "en_GB"); + map.put("dateFormat", "dd MMMM yyyy"); + map.put("transactionDate", date); + map.put("transactionAmount", transactionAmount); + String json = new Gson().toJson(map); + System.out.println(json); + return json; + } + public HashMap getPrepayAmount(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, final Integer loanID) { - final String URL = "/mifosng-provider/api/v1/loans/" + loanID + "/transactions/template?command=prepayLoan&" + Utils.TENANT_IDENTIFIER; + final String URL = "/mifosng-provider/api/v1/loans/" + loanID + "/transactions/template?command=prepayLoan&" + + Utils.TENANT_IDENTIFIER; final HashMap response = Utils.performServerGet(requestSpec, responseSpec, URL, ""); return response; } diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/savings/SavingsAccountHelper.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/savings/SavingsAccountHelper.java index 3d2345db5..4af3c976e 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/savings/SavingsAccountHelper.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/savings/SavingsAccountHelper.java @@ -12,6 +12,7 @@ import java.util.HashMap; import java.util.List; import java.util.Locale; +import org.junit.Assert; import org.mifosplatform.integrationtests.common.CommonConstants; import org.mifosplatform.integrationtests.common.Utils; @@ -45,6 +46,7 @@ public class SavingsAccountHelper { public static final String CREATED_DATE_MINUS_ONE = "07 January 2013"; public static final String TRANSACTION_DATE = "01 March 2013"; public static final String LAST_TRANSACTION_DATE = "01 March 2013"; + public static final String ACCOUNT_TYPE_INDIVIDUAL = "INDIVIDUAL"; public SavingsAccountHelper(final RequestSpecification requestSpec, final ResponseSpecification responseSpec) { this.requestSpec = requestSpec; @@ -59,12 +61,12 @@ public class SavingsAccountHelper { } public Integer applyForSavingsApplication(final Integer ID, final Integer savingsProductID, final String accountType) { - return applyForSavingsApplicationOnDate(ID, savingsProductID, accountType, CREATED_DATE); + return applyForSavingsApplicationOnDate(ID, savingsProductID, accountType, CREATED_DATE); } - + public Integer applyForSavingsApplicationOnDate(final Integer ID, final Integer savingsProductID, final String accountType, - final String submittedOnDate) { - System.out.println("--------------------------------APPLYING FOR SAVINGS APPLICATION--------------------------------"); + final String submittedOnDate) { + System.out.println("--------------------------------APPLYING FOR SAVINGS APPLICATION--------------------------------"); final String savingsApplicationJSON = new SavingsApplicationTestBuilder() // .withSubmittedOnDate(submittedOnDate) // .build(ID.toString(), savingsProductID.toString(), accountType); @@ -82,15 +84,15 @@ public class SavingsAccountHelper { } public HashMap approveSavings(final Integer savingsID) { - return approveSavingsOnDate(savingsID, null); + return approveSavingsOnDate(savingsID, null); } - + public HashMap approveSavingsOnDate(final Integer savingsID, final String approvalDate) { - System.out.println("--------------------------------- APPROVING SAVINGS APPLICATION ------------------------------------"); - final String savingsOperationURL = createSavingsOperationURL(APPROVE_SAVINGS_COMMAND, savingsID); - if(approvalDate == null || approvalDate == "") - return performSavingApplicationActions(savingsOperationURL, getApproveSavingsAsJSON()); - return performSavingApplicationActions(savingsOperationURL, getApproveSavingsAsJsonOnDate(approvalDate)); + System.out.println("--------------------------------- APPROVING SAVINGS APPLICATION ------------------------------------"); + final String savingsOperationURL = createSavingsOperationURL(APPROVE_SAVINGS_COMMAND, savingsID); + if (approvalDate == null || approvalDate == "") + return performSavingApplicationActions(savingsOperationURL, getApproveSavingsAsJSON()); + return performSavingApplicationActions(savingsOperationURL, getApproveSavingsAsJsonOnDate(approvalDate)); } public HashMap undoApproval(final Integer savingsID) { @@ -124,7 +126,8 @@ public class SavingsAccountHelper { public HashMap closeSavingsAccount(final Integer savingsID, String withdrawBalance) { System.out.println("---------------------------------- CLOSE SAVINGS APPLICATION ----------------------------------"); - return performSavingApplicationActions(createSavingsOperationURL(CLOSE_SAVINGS_COMMAND, savingsID), getCloseAccountJSON(withdrawBalance, LAST_TRANSACTION_DATE)); + return performSavingApplicationActions(createSavingsOperationURL(CLOSE_SAVINGS_COMMAND, savingsID), + getCloseAccountJSON(withdrawBalance, LAST_TRANSACTION_DATE)); } public Object deleteSavingsApplication(final Integer savingsId, final String jsonAttributeToGetBack) { @@ -199,9 +202,9 @@ public class SavingsAccountHelper { private String getApproveSavingsAsJSON() { return getApproveSavingsAsJsonOnDate(CREATED_DATE_PLUS_ONE); } - + private String getApproveSavingsAsJsonOnDate(final String approvalDate) { - final HashMap map = new HashMap<>(); + final HashMap map = new HashMap<>(); map.put("locale", CommonConstants.locale); map.put("dateFormat", CommonConstants.dateFormat); map.put("approvedOnDate", approvalDate); @@ -352,13 +355,19 @@ public class SavingsAccountHelper { final HashMap response = Utils.performServerGet(requestSpec, responseSpec, URL, "summary"); return response; } - + public HashMap getSavingsDetails(final Integer savingsID) { final String URL = SAVINGS_ACCOUNT_URL + "/" + savingsID + "?associations=all&" + Utils.TENANT_IDENTIFIER; final HashMap response = Utils.performServerGet(requestSpec, responseSpec, URL, ""); return response; } + public Object getSavingsDetails(final Integer savingsID, final String returnAttribute) { + final String URL = SAVINGS_ACCOUNT_URL + "/" + savingsID + "?" + Utils.TENANT_IDENTIFIER; + final Object response = Utils.performServerGet(requestSpec, responseSpec, URL, returnAttribute); + return response; + } + private HashMap performSavingApplicationActions(final String postURLForSavingsTransaction, final String jsonToBeSent) { HashMap status = null; final HashMap response = Utils.performServerPost(this.requestSpec, this.responseSpec, postURLForSavingsTransaction, jsonToBeSent, @@ -421,4 +430,38 @@ public class SavingsAccountHelper { String josn = new Gson().toJson(map); return josn; } + + public static Integer openSavingsAccount(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, + final Integer clientId, final String minimumOpeningBalance) { + final Integer savingsProductID = createSavingsProduct(requestSpec, responseSpec, minimumOpeningBalance); + Assert.assertNotNull(savingsProductID); + + SavingsAccountHelper savingsAccountHelper = new SavingsAccountHelper(requestSpec, responseSpec); + + final Integer savingsId = savingsAccountHelper.applyForSavingsApplication(clientId, savingsProductID, ACCOUNT_TYPE_INDIVIDUAL); + Assert.assertNotNull(savingsProductID); + + HashMap savingsStatusHashMap = SavingsStatusChecker.getStatusOfSavings(requestSpec, responseSpec, savingsId); + SavingsStatusChecker.verifySavingsIsPending(savingsStatusHashMap); + + savingsStatusHashMap = savingsAccountHelper.approveSavings(savingsId); + SavingsStatusChecker.verifySavingsIsApproved(savingsStatusHashMap); + + savingsStatusHashMap = savingsAccountHelper.activateSavings(savingsId); + SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap); + return savingsId; + } + + private static Integer createSavingsProduct(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, + final String minOpenningBalance) { + System.out.println("------------------------------CREATING NEW SAVINGS PRODUCT ---------------------------------------"); + SavingsProductHelper savingsProductHelper = new SavingsProductHelper(); + final String savingsProductJSON = savingsProductHelper // + .withInterestCompoundingPeriodTypeAsDaily() // + .withInterestPostingPeriodTypeAsMonthly() // + .withInterestCalculationPeriodTypeAsDailyBalance() // + .withMinimumOpenningBalance(minOpenningBalance).build(); + return SavingsProductHelper.createSavingsProduct(savingsProductJSON, requestSpec, responseSpec); + } + } \ No newline at end of file diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/loanaccount/guarantor/GuarantorHelper.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/loanaccount/guarantor/GuarantorHelper.java new file mode 100755 index 000000000..fb4f3389f --- /dev/null +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/loanaccount/guarantor/GuarantorHelper.java @@ -0,0 +1,59 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.integrationtests.loanaccount.guarantor; + +import java.util.HashMap; +import java.util.List; + +import org.mifosplatform.integrationtests.common.CommonConstants; +import org.mifosplatform.integrationtests.common.Utils; + +import com.jayway.restassured.specification.RequestSpecification; +import com.jayway.restassured.specification.ResponseSpecification; + +public class GuarantorHelper { + + private static final String LOAN_URL = "/mifosng-provider/api/v1/loans/"; + private static final String GUARANTOR_API_URL = "/guarantors/"; + private static final String TENANT = "?" + Utils.TENANT_IDENTIFIER; + private final RequestSpecification requestSpec; + private final ResponseSpecification responseSpec; + + public GuarantorHelper(final RequestSpecification requestSpec, final ResponseSpecification responseSpec) { + this.requestSpec = requestSpec; + this.responseSpec = responseSpec; + } + + public Integer createGuarantor(final Integer loanId, final String guarantorJSON) { + return Utils.performServerPost(this.requestSpec, this.responseSpec, LOAN_URL + loanId + GUARANTOR_API_URL + TENANT, guarantorJSON, + CommonConstants.RESPONSE_RESOURCE_ID); + } + + public HashMap updateGuarantor(final Integer guarantorId, final Integer loanId, final String guarantorJSON) { + return Utils.performServerPut(this.requestSpec, this.responseSpec, LOAN_URL + loanId + GUARANTOR_API_URL + guarantorId + TENANT, + guarantorJSON, CommonConstants.RESPONSE_CHANGES); + } + + public HashMap deleteGuarantor(final Integer guarantorId, final Integer fundId, final Integer loanId) { + return Utils.performServerDelete(this.requestSpec, this.responseSpec, LOAN_URL + loanId + GUARANTOR_API_URL + guarantorId + TENANT + + "&guarantorFundingId=" + fundId, ""); + } + + public HashMap deleteGuarantor(final Integer guarantorId, final Integer loanId) { + return Utils.performServerDelete(this.requestSpec, this.responseSpec, LOAN_URL + loanId + GUARANTOR_API_URL + guarantorId + TENANT, + ""); + } + + public Object getGuarantor(final Integer guarantorId, final Integer loanId, final String jsonToGetBack) { + return Utils.performServerGet(this.requestSpec, this.responseSpec, LOAN_URL + loanId + GUARANTOR_API_URL + guarantorId + TENANT, + jsonToGetBack); + } + + public List getAllGuarantor(final Integer loanId) { + return Utils.performServerGet(this.requestSpec, this.responseSpec, LOAN_URL + loanId + GUARANTOR_API_URL + TENANT, ""); + } + +} diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/loanaccount/guarantor/GuarantorTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/loanaccount/guarantor/GuarantorTest.java new file mode 100755 index 000000000..9f5242ac8 --- /dev/null +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/loanaccount/guarantor/GuarantorTest.java @@ -0,0 +1,607 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.integrationtests.loanaccount.guarantor; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mifosplatform.integrationtests.common.ClientHelper; +import org.mifosplatform.integrationtests.common.CommonConstants; +import org.mifosplatform.integrationtests.common.Utils; +import org.mifosplatform.integrationtests.common.loans.LoanApplicationTestBuilder; +import org.mifosplatform.integrationtests.common.loans.LoanProductTestBuilder; +import org.mifosplatform.integrationtests.common.loans.LoanStatusChecker; +import org.mifosplatform.integrationtests.common.loans.LoanTransactionHelper; +import org.mifosplatform.integrationtests.common.savings.SavingsAccountHelper; + +import com.jayway.restassured.builder.RequestSpecBuilder; +import com.jayway.restassured.builder.ResponseSpecBuilder; +import com.jayway.restassured.http.ContentType; +import com.jayway.restassured.specification.RequestSpecification; +import com.jayway.restassured.specification.ResponseSpecification; + +public class GuarantorTest { + + private ResponseSpecification responseSpec; + private RequestSpecification requestSpec; + private LoanTransactionHelper loanTransactionHelper; + private GuarantorHelper guarantorHelper; + private SavingsAccountHelper savingsAccountHelper; + private final Float self1_balance = new Float(5000); + private final Float external1_balance = new Float(5000); + private final Float external2_balance = new Float(5000); + private final Float self1_guarantee = new Float(2000); + private final Float external1_guarantee = new Float(2000); + private final Float external2_guarantee = new Float(1000); + + @Before + public void setUp() throws Exception { + Utils.initializeRESTAssured(); + this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); + this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); + this.responseSpec = new ResponseSpecBuilder().build(); + this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec); + this.guarantorHelper = new GuarantorHelper(this.requestSpec, this.responseSpec); + savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Test + public void testGuarantor() { + + Float self1_hold_funds = new Float(0); + Float external1_hold_funds = new Float(0); + Float external2_hold_funds = new Float(0); + final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec); + ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID); + final Integer clientID_external = ClientHelper.createClient(this.requestSpec, this.responseSpec); + final Integer clientID_external2 = ClientHelper.createClient(this.requestSpec, this.responseSpec); + + ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID_external); + + final Integer selfSavigsId = SavingsAccountHelper.openSavingsAccount(this.requestSpec, this.responseSpec, clientID, + String.valueOf(self1_balance)); + final Integer externalSavigsId_1 = SavingsAccountHelper.openSavingsAccount(this.requestSpec, this.responseSpec, clientID_external, + String.valueOf(external1_balance)); + final Integer externalSavigsId_2 = SavingsAccountHelper.openSavingsAccount(this.requestSpec, this.responseSpec, clientID_external2, + String.valueOf(external2_balance)); + + final Integer loanProductID = createLoanProductWithHoldFunds("50", "20", "20"); + DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy", Locale.US); + Calendar todaysDate = Calendar.getInstance(); + todaysDate.add(Calendar.DAY_OF_MONTH, -7 * 4); + String LOAN_DISBURSEMENT_DATE = dateFormat.format(todaysDate.getTime()); + final Integer loanID = applyForLoanApplication(clientID, loanProductID, LOAN_DISBURSEMENT_DATE); + Assert.assertNotNull(loanID); + HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID); + LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap); + + String guarantorJSON = new GuarantorTestBuilder().externalCustomer().build(); + Integer externalGuarantor = this.guarantorHelper.createGuarantor(loanID, guarantorJSON); + Assert.assertNotNull(externalGuarantor); + + guarantorJSON = new GuarantorTestBuilder().existingCustomerWithoutGuaranteeAmount(String.valueOf(clientID_external)).build(); + Integer withoutGuaranteeAmount = this.guarantorHelper.createGuarantor(loanID, guarantorJSON); + Assert.assertNotNull(withoutGuaranteeAmount); + + ArrayList errorData = (ArrayList) this.loanTransactionHelper.approveLoan(LOAN_DISBURSEMENT_DATE, null, loanID, + CommonConstants.RESPONSE_ERROR); + assertTrue(checkForErrorCode(errorData, "validation.msg.loan.guarantor.min.self.guarantee.required")); + assertTrue(checkForErrorCode(errorData, "validation.msg.loan.guarantor.min.external.guarantee.required")); + assertTrue(checkForErrorCode(errorData, "validation.msg.loan.guarantor.mandated.guarantee.required")); + + guarantorJSON = new GuarantorTestBuilder().existingCustomerWithGuaranteeAmount(String.valueOf(clientID), + String.valueOf(selfSavigsId), String.valueOf(self1_guarantee)).build(); + Integer selfGuarantee = this.guarantorHelper.createGuarantor(loanID, guarantorJSON); + verifySavingsOnHoldBalance(selfSavigsId, null); + Assert.assertNotNull(selfGuarantee); + + errorData = (ArrayList) this.loanTransactionHelper.approveLoan(LOAN_DISBURSEMENT_DATE, null, loanID, + CommonConstants.RESPONSE_ERROR); + assertFalse(checkForErrorCode(errorData, "validation.msg.loan.guarantor.min.self.guarantee.required")); + assertTrue(checkForErrorCode(errorData, "validation.msg.loan.guarantor.min.external.guarantee.required")); + assertTrue(checkForErrorCode(errorData, "validation.msg.loan.guarantor.mandated.guarantee.required")); + + guarantorJSON = new GuarantorTestBuilder().existingCustomerWithGuaranteeAmount(String.valueOf(clientID_external), + String.valueOf(externalSavigsId_1), String.valueOf(external1_guarantee)).build(); + Integer externalGuarantee_1 = this.guarantorHelper.createGuarantor(loanID, guarantorJSON); + verifySavingsOnHoldBalance(externalSavigsId_1, null); + Assert.assertNotNull(externalGuarantee_1); + + errorData = (ArrayList) this.loanTransactionHelper.approveLoan(LOAN_DISBURSEMENT_DATE, null, loanID, + CommonConstants.RESPONSE_ERROR); + assertFalse(checkForErrorCode(errorData, "validation.msg.loan.guarantor.min.self.guarantee.required")); + assertFalse(checkForErrorCode(errorData, "validation.msg.loan.guarantor.min.external.guarantee.required")); + assertTrue(checkForErrorCode(errorData, "validation.msg.loan.guarantor.mandated.guarantee.required")); + + guarantorJSON = new GuarantorTestBuilder().existingCustomerWithGuaranteeAmount(String.valueOf(clientID_external2), + String.valueOf(externalSavigsId_2), String.valueOf(external2_guarantee)).build(); + Integer externalGuarantee_2 = this.guarantorHelper.createGuarantor(loanID, guarantorJSON); + verifySavingsOnHoldBalance(externalSavigsId_2, null); + Assert.assertNotNull(externalGuarantee_2); + + System.out.println("-----------------------------------APPROVE LOAN-----------------------------------------"); + loanStatusHashMap = this.loanTransactionHelper.approveLoan(LOAN_DISBURSEMENT_DATE, loanID); + LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); + LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap); + self1_hold_funds += self1_guarantee; + external1_hold_funds += external1_guarantee; + external2_hold_funds += external2_guarantee; + verifySavingsOnHoldBalance(selfSavigsId, self1_hold_funds); + verifySavingsOnHoldBalance(externalSavigsId_1, external1_hold_funds); + verifySavingsOnHoldBalance(externalSavigsId_2, external2_hold_funds); + + System.out.println("-----------------------------------UNDO APPROVE LOAN-----------------------------------------"); + loanStatusHashMap = this.loanTransactionHelper.undoApproval(loanID); + LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap); + verifySavingsOnHoldBalance(selfSavigsId, new Float(0)); + verifySavingsOnHoldBalance(externalSavigsId_1, new Float(0)); + verifySavingsOnHoldBalance(externalSavigsId_2, new Float(0)); + + System.out.println("-----------------------------------APPROVE LOAN-----------------------------------------"); + loanStatusHashMap = this.loanTransactionHelper.approveLoan(LOAN_DISBURSEMENT_DATE, loanID); + LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); + LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap); + verifySavingsOnHoldBalance(selfSavigsId, self1_hold_funds); + verifySavingsOnHoldBalance(externalSavigsId_1, external1_hold_funds); + verifySavingsOnHoldBalance(externalSavigsId_2, external2_hold_funds); + + System.out.println("-------------------------------DISBURSE LOAN-------------------------------------------"); + loanStatusHashMap = this.loanTransactionHelper.disburseLoan(LOAN_DISBURSEMENT_DATE, loanID); + LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap); + + // First repayment + ArrayList loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); + todaysDate = Calendar.getInstance(); + todaysDate.add(Calendar.DAY_OF_MONTH, -7 * 3); + String LOAN_REPAYMENT_DATE = dateFormat.format(todaysDate.getTime()); + Float totalDueForCurrentPeriod = (Float) loanSchedule.get(1).get("totalDueForPeriod"); + external1_hold_funds -= new Float(827.5867); + external2_hold_funds -= new Float(413.7933); + this.loanTransactionHelper.makeRepayment(LOAN_REPAYMENT_DATE, totalDueForCurrentPeriod, loanID); + verifySavingsOnHoldBalance(selfSavigsId, self1_hold_funds); + verifySavingsOnHoldBalance(externalSavigsId_1, external1_hold_funds); + verifySavingsOnHoldBalance(externalSavigsId_2, external2_hold_funds); + + // Second repayment + todaysDate = Calendar.getInstance(); + todaysDate.add(Calendar.DAY_OF_MONTH, -7 * 2); + LOAN_REPAYMENT_DATE = dateFormat.format(todaysDate.getTime()); + totalDueForCurrentPeriod = (Float) loanSchedule.get(2).get("totalDueForPeriod"); + external1_hold_funds -= new Float(831.4067); + external2_hold_funds -= new Float(415.7033333); + this.loanTransactionHelper.makeRepayment(LOAN_REPAYMENT_DATE, totalDueForCurrentPeriod, loanID); + verifySavingsOnHoldBalance(selfSavigsId, self1_hold_funds); + verifySavingsOnHoldBalance(externalSavigsId_1, external1_hold_funds); + verifySavingsOnHoldBalance(externalSavigsId_2, external2_hold_funds); + + // third repayment + todaysDate = Calendar.getInstance(); + todaysDate.add(Calendar.DAY_OF_MONTH, -7); + LOAN_REPAYMENT_DATE = dateFormat.format(todaysDate.getTime()); + totalDueForCurrentPeriod = (Float) loanSchedule.get(3).get("totalDueForPeriod"); + self1_hold_funds -= new Float(741.355); + this.loanTransactionHelper.makeRepayment(LOAN_REPAYMENT_DATE, totalDueForCurrentPeriod, loanID); + verifySavingsOnHoldBalance(selfSavigsId, self1_hold_funds); + verifySavingsOnHoldBalance(externalSavigsId_1, new Float(0)); + verifySavingsOnHoldBalance(externalSavigsId_2, new Float(0)); + + // forth repayment + todaysDate = Calendar.getInstance(); + LOAN_REPAYMENT_DATE = dateFormat.format(todaysDate.getTime()); + totalDueForCurrentPeriod = (Float) loanSchedule.get(3).get("totalDueForPeriod"); + this.loanTransactionHelper.makeRepayment(LOAN_REPAYMENT_DATE, totalDueForCurrentPeriod, loanID); + verifySavingsOnHoldBalance(selfSavigsId, new Float(0)); + verifySavingsOnHoldBalance(externalSavigsId_1, new Float(0)); + verifySavingsOnHoldBalance(externalSavigsId_2, new Float(0)); + + loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID); + LoanStatusChecker.verifyLoanAccountIsClosed(loanStatusHashMap); + + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Test + public void testGuarantor_UNDO_DISBURSAL() { + + Float self1_hold_funds = new Float(0); + Float external1_hold_funds = new Float(0); + Float external2_hold_funds = new Float(0); + final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec); + ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID); + final Integer clientID_external = ClientHelper.createClient(this.requestSpec, this.responseSpec); + final Integer clientID_external2 = ClientHelper.createClient(this.requestSpec, this.responseSpec); + + ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID_external); + + final Integer selfSavigsId = SavingsAccountHelper.openSavingsAccount(this.requestSpec, this.responseSpec, clientID, + String.valueOf(self1_balance)); + final Integer externalSavigsId_1 = SavingsAccountHelper.openSavingsAccount(this.requestSpec, this.responseSpec, clientID_external, + String.valueOf(external1_balance)); + final Integer externalSavigsId_3 = SavingsAccountHelper.openSavingsAccount(this.requestSpec, this.responseSpec, clientID_external, + String.valueOf(external1_balance)); + final Integer externalSavigsId_2 = SavingsAccountHelper.openSavingsAccount(this.requestSpec, this.responseSpec, clientID_external2, + String.valueOf(external2_balance)); + + final Integer loanProductID = createLoanProductWithHoldFunds("50", "20", "20"); + DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy", Locale.US); + Calendar todaysDate = Calendar.getInstance(); + todaysDate.add(Calendar.DAY_OF_MONTH, -7 * 4); + String LOAN_DISBURSEMENT_DATE = dateFormat.format(todaysDate.getTime()); + final Integer loanID = applyForLoanApplication(clientID, loanProductID, LOAN_DISBURSEMENT_DATE); + Assert.assertNotNull(loanID); + HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID); + LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap); + + String guarantorJSON = new GuarantorTestBuilder().externalCustomer().build(); + Integer externalGuarantor = this.guarantorHelper.createGuarantor(loanID, guarantorJSON); + Assert.assertNotNull(externalGuarantor); + + guarantorJSON = new GuarantorTestBuilder().existingCustomerWithoutGuaranteeAmount(String.valueOf(clientID_external)).build(); + Integer withoutGuaranteeAmount = this.guarantorHelper.createGuarantor(loanID, guarantorJSON); + Assert.assertNotNull(withoutGuaranteeAmount); + + ArrayList errorData = (ArrayList) this.loanTransactionHelper.approveLoan(LOAN_DISBURSEMENT_DATE, null, loanID, + CommonConstants.RESPONSE_ERROR); + assertTrue(checkForErrorCode(errorData, "validation.msg.loan.guarantor.min.self.guarantee.required")); + assertTrue(checkForErrorCode(errorData, "validation.msg.loan.guarantor.min.external.guarantee.required")); + assertTrue(checkForErrorCode(errorData, "validation.msg.loan.guarantor.mandated.guarantee.required")); + + guarantorJSON = new GuarantorTestBuilder().existingCustomerWithGuaranteeAmount(String.valueOf(clientID), + String.valueOf(selfSavigsId), String.valueOf(self1_guarantee)).build(); + Integer selfGuarantee = this.guarantorHelper.createGuarantor(loanID, guarantorJSON); + verifySavingsOnHoldBalance(selfSavigsId, null); + Assert.assertNotNull(selfGuarantee); + + errorData = (ArrayList) this.loanTransactionHelper.approveLoan(LOAN_DISBURSEMENT_DATE, null, loanID, + CommonConstants.RESPONSE_ERROR); + assertFalse(checkForErrorCode(errorData, "validation.msg.loan.guarantor.min.self.guarantee.required")); + assertTrue(checkForErrorCode(errorData, "validation.msg.loan.guarantor.min.external.guarantee.required")); + assertTrue(checkForErrorCode(errorData, "validation.msg.loan.guarantor.mandated.guarantee.required")); + + guarantorJSON = new GuarantorTestBuilder().existingCustomerWithGuaranteeAmount(String.valueOf(clientID_external), + String.valueOf(externalSavigsId_1), String.valueOf(external1_guarantee)).build(); + Integer externalGuarantee_1 = this.guarantorHelper.createGuarantor(loanID, guarantorJSON); + verifySavingsOnHoldBalance(externalSavigsId_1, null); + Assert.assertNotNull(externalGuarantee_1); + + errorData = (ArrayList) this.loanTransactionHelper.approveLoan(LOAN_DISBURSEMENT_DATE, null, loanID, + CommonConstants.RESPONSE_ERROR); + assertFalse(checkForErrorCode(errorData, "validation.msg.loan.guarantor.min.self.guarantee.required")); + assertFalse(checkForErrorCode(errorData, "validation.msg.loan.guarantor.min.external.guarantee.required")); + assertTrue(checkForErrorCode(errorData, "validation.msg.loan.guarantor.mandated.guarantee.required")); + + guarantorJSON = new GuarantorTestBuilder().existingCustomerWithGuaranteeAmount(String.valueOf(clientID_external2), + String.valueOf(externalSavigsId_2), String.valueOf(external2_guarantee)).build(); + Integer externalGuarantee_2 = this.guarantorHelper.createGuarantor(loanID, guarantorJSON); + Assert.assertNotNull(externalGuarantee_2); + verifySavingsOnHoldBalance(externalSavigsId_2, null); + + System.out.println("-----------------------------------APPROVE LOAN-----------------------------------------"); + loanStatusHashMap = this.loanTransactionHelper.approveLoan(LOAN_DISBURSEMENT_DATE, loanID); + LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); + LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap); + self1_hold_funds += self1_guarantee; + external1_hold_funds += external1_guarantee; + external2_hold_funds += external2_guarantee; + verifySavingsOnHoldBalance(selfSavigsId, self1_hold_funds); + verifySavingsOnHoldBalance(externalSavigsId_1, external1_hold_funds); + verifySavingsOnHoldBalance(externalSavigsId_2, external2_hold_funds); + + System.out.println("-----------------------------------UNDO APPROVE LOAN-----------------------------------------"); + loanStatusHashMap = this.loanTransactionHelper.undoApproval(loanID); + LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap); + verifySavingsOnHoldBalance(selfSavigsId, new Float(0)); + verifySavingsOnHoldBalance(externalSavigsId_1, new Float(0)); + verifySavingsOnHoldBalance(externalSavigsId_2, new Float(0)); + + System.out.println("-----------------------------------APPROVE LOAN-----------------------------------------"); + loanStatusHashMap = this.loanTransactionHelper.approveLoan(LOAN_DISBURSEMENT_DATE, loanID); + LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); + LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap); + verifySavingsOnHoldBalance(selfSavigsId, self1_hold_funds); + verifySavingsOnHoldBalance(externalSavigsId_1, external1_hold_funds); + verifySavingsOnHoldBalance(externalSavigsId_2, external2_hold_funds); + List guarantors = this.guarantorHelper.getAllGuarantor(loanID); + this.guarantorHelper.deleteGuarantor(externalGuarantor, loanID); + assertFalse((Boolean) this.guarantorHelper.getGuarantor(externalGuarantor, loanID, "status")); + HashMap errorlog = this.guarantorHelper.deleteGuarantor(withoutGuaranteeAmount, loanID); + ArrayList error = (ArrayList) errorlog.get(CommonConstants.RESPONSE_ERROR); + assertTrue(checkForErrorCode(error, "error.msg.loan.guarantor.not.found")); + guarantors = this.guarantorHelper.getAllGuarantor(loanID); + assertEquals(4, guarantors.size()); + List externalGuarantee_1_details = (List) this.guarantorHelper.getGuarantor(externalGuarantee_1, loanID, + "guarantorFundingDetails"); + Integer fundDetailId = (Integer) externalGuarantee_1_details.get(0).get("id"); + errorlog = this.guarantorHelper.deleteGuarantor(externalGuarantee_1, fundDetailId, loanID); + error = (ArrayList) errorlog.get(CommonConstants.RESPONSE_ERROR); + assertTrue(checkForErrorCode(error, "validation.msg.loan.guarantor.min.external.guarantee.required")); + + guarantorJSON = new GuarantorTestBuilder().existingCustomerWithGuaranteeAmount(String.valueOf(clientID_external), + String.valueOf(externalSavigsId_3), String.valueOf(external1_guarantee)).build(); + Integer externalGuarantee_3 = this.guarantorHelper.createGuarantor(loanID, guarantorJSON); + verifySavingsOnHoldBalance(externalSavigsId_3, external1_guarantee); + Assert.assertNotNull(externalGuarantee_3); + + this.guarantorHelper.deleteGuarantor(externalGuarantee_1, fundDetailId, loanID); + guarantors = this.guarantorHelper.getAllGuarantor(loanID); + assertEquals(4, guarantors.size()); + externalGuarantee_1_details = (List) this.guarantorHelper.getGuarantor(externalGuarantee_1, loanID, + "guarantorFundingDetails"); + assertEquals(2, externalGuarantee_1_details.size()); + + for (HashMap map : externalGuarantee_1_details) { + if (map.get("id").equals(fundDetailId)) { + HashMap status = (HashMap) map.get("status"); + assertEquals("guarantorFundStatusType.withdrawn", status.get("code")); + } + } + + System.out.println("-------------------------------DISBURSE LOAN-------------------------------------------"); + loanStatusHashMap = this.loanTransactionHelper.disburseLoan(LOAN_DISBURSEMENT_DATE, loanID); + LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap); + + // First repayment + ArrayList loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); + todaysDate = Calendar.getInstance(); + todaysDate.add(Calendar.DAY_OF_MONTH, -7 * 3); + String LOAN_REPAYMENT_DATE = dateFormat.format(todaysDate.getTime()); + Float totalDueForCurrentPeriod = (Float) loanSchedule.get(1).get("totalDueForPeriod"); + external1_hold_funds -= new Float(827.5867); + external2_hold_funds -= new Float(413.7933); + this.loanTransactionHelper.makeRepayment(LOAN_REPAYMENT_DATE, totalDueForCurrentPeriod, loanID); + verifySavingsOnHoldBalance(selfSavigsId, self1_hold_funds); + verifySavingsOnHoldBalance(externalSavigsId_3, external1_hold_funds); + verifySavingsOnHoldBalance(externalSavigsId_2, external2_hold_funds); + + // Second repayment + todaysDate = Calendar.getInstance(); + todaysDate.add(Calendar.DAY_OF_MONTH, -7 * 2); + LOAN_REPAYMENT_DATE = dateFormat.format(todaysDate.getTime()); + totalDueForCurrentPeriod = (Float) loanSchedule.get(2).get("totalDueForPeriod"); + external1_hold_funds -= new Float(831.4067); + external2_hold_funds -= new Float(415.7033333); + this.loanTransactionHelper.makeRepayment(LOAN_REPAYMENT_DATE, totalDueForCurrentPeriod, loanID); + verifySavingsOnHoldBalance(selfSavigsId, self1_hold_funds); + verifySavingsOnHoldBalance(externalSavigsId_3, external1_hold_funds); + verifySavingsOnHoldBalance(externalSavigsId_2, external2_hold_funds); + + // third repayment + todaysDate = Calendar.getInstance(); + todaysDate.add(Calendar.DAY_OF_MONTH, -7); + LOAN_REPAYMENT_DATE = dateFormat.format(todaysDate.getTime()); + totalDueForCurrentPeriod = (Float) loanSchedule.get(3).get("totalDueForPeriod"); + Float self1_hold_funds_temp = self1_hold_funds - new Float(741.355); + HashMap transactionDetail = this.loanTransactionHelper.makeRepayment(LOAN_REPAYMENT_DATE, totalDueForCurrentPeriod, loanID); + verifySavingsOnHoldBalance(selfSavigsId, self1_hold_funds_temp); + verifySavingsOnHoldBalance(externalSavigsId_3, new Float(0)); + verifySavingsOnHoldBalance(externalSavigsId_2, new Float(0)); + + // undo repayment + this.loanTransactionHelper.adjustLoanTransaction(loanID, (Integer) transactionDetail.get(CommonConstants.RESPONSE_RESOURCE_ID), + LOAN_REPAYMENT_DATE, "0", ""); + verifySavingsOnHoldBalance(selfSavigsId, self1_hold_funds); + verifySavingsOnHoldBalance(externalSavigsId_3, external1_hold_funds); + verifySavingsOnHoldBalance(externalSavigsId_2, external2_hold_funds); + + // undo disbursal + loanStatusHashMap = this.loanTransactionHelper.undoDisbursal(loanID); + LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); + LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap); + verifySavingsOnHoldBalance(selfSavigsId, new Float(self1_guarantee)); + verifySavingsOnHoldBalance(externalSavigsId_3, new Float(external1_guarantee)); + verifySavingsOnHoldBalance(externalSavigsId_2, new Float(external2_guarantee)); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Test + public void testGuarantor_RECOVER_GUARANTEES() { + + Float self1_hold_funds = new Float(0); + Float external1_hold_funds = new Float(0); + final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec); + ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID); + final Integer clientID_external = ClientHelper.createClient(this.requestSpec, this.responseSpec); + ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID_external); + + final Integer selfSavigsId = SavingsAccountHelper.openSavingsAccount(this.requestSpec, this.responseSpec, clientID, + String.valueOf(self1_balance)); + final Integer externalSavigsId_1 = SavingsAccountHelper.openSavingsAccount(this.requestSpec, this.responseSpec, clientID_external, + String.valueOf(external1_balance)); + + final Integer loanProductID = createLoanProductWithHoldFunds("40", "20", "20"); + DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy", Locale.US); + Calendar todaysDate = Calendar.getInstance(); + todaysDate.add(Calendar.DAY_OF_MONTH, -21); + String LOAN_DISBURSEMENT_DATE = dateFormat.format(todaysDate.getTime()); + final Integer loanID = applyForLoanApplication(clientID, loanProductID, LOAN_DISBURSEMENT_DATE); + Assert.assertNotNull(loanID); + HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID); + LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap); + + String guarantorJSON = new GuarantorTestBuilder().existingCustomerWithGuaranteeAmount(String.valueOf(clientID), + String.valueOf(selfSavigsId), String.valueOf(self1_guarantee)).build(); + Integer selfGuarantee = this.guarantorHelper.createGuarantor(loanID, guarantorJSON); + verifySavingsOnHoldBalance(selfSavigsId, null); + Assert.assertNotNull(selfGuarantee); + + guarantorJSON = new GuarantorTestBuilder().existingCustomerWithGuaranteeAmount(String.valueOf(clientID_external), + String.valueOf(externalSavigsId_1), String.valueOf(external1_guarantee)).build(); + Integer externalGuarantee_1 = this.guarantorHelper.createGuarantor(loanID, guarantorJSON); + verifySavingsOnHoldBalance(externalSavigsId_1, null); + Assert.assertNotNull(externalGuarantee_1); + + System.out.println("-----------------------------------APPROVE LOAN-----------------------------------------"); + loanStatusHashMap = this.loanTransactionHelper.approveLoan(LOAN_DISBURSEMENT_DATE, loanID); + LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); + LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap); + self1_hold_funds += self1_guarantee; + external1_hold_funds += external1_guarantee; + verifySavingsOnHoldBalance(selfSavigsId, self1_hold_funds); + verifySavingsOnHoldBalance(externalSavigsId_1, external1_hold_funds); + + System.out.println("-------------------------------DISBURSE LOAN-------------------------------------------"); + loanStatusHashMap = this.loanTransactionHelper.disburseLoan(LOAN_DISBURSEMENT_DATE, loanID); + LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap); + + // First repayment + ArrayList loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); + todaysDate = Calendar.getInstance(); + todaysDate.add(Calendar.DAY_OF_MONTH, -14); + String LOAN_REPAYMENT_DATE = dateFormat.format(todaysDate.getTime()); + Float totalDueForCurrentPeriod = (Float) loanSchedule.get(1).get("totalDueForPeriod"); + external1_hold_funds -= new Float(993.104); + this.loanTransactionHelper.makeRepayment(LOAN_REPAYMENT_DATE, totalDueForCurrentPeriod, loanID); + verifySavingsOnHoldBalance(selfSavigsId, self1_hold_funds); + verifySavingsOnHoldBalance(externalSavigsId_1, external1_hold_funds); + + this.loanTransactionHelper.recoverFromGuarantor(loanID); + verifySavingsBalanceAndOnHoldBalance(selfSavigsId, new Float(0), self1_balance - self1_hold_funds); + verifySavingsBalanceAndOnHoldBalance(externalSavigsId_1, new Float(0), external1_balance - external1_hold_funds); + + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Test + public void testGuarantor_WRITE_OFF_LOAN() { + + Float self1_hold_funds = new Float(0); + Float external1_hold_funds = new Float(0); + final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec); + ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID); + final Integer clientID_external = ClientHelper.createClient(this.requestSpec, this.responseSpec); + ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID_external); + + final Integer selfSavigsId = SavingsAccountHelper.openSavingsAccount(this.requestSpec, this.responseSpec, clientID, + String.valueOf(self1_balance)); + final Integer externalSavigsId_1 = SavingsAccountHelper.openSavingsAccount(this.requestSpec, this.responseSpec, clientID_external, + String.valueOf(external1_balance)); + + final Integer loanProductID = createLoanProductWithHoldFunds("40", "20", "20"); + DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy", Locale.US); + Calendar todaysDate = Calendar.getInstance(); + todaysDate.add(Calendar.DAY_OF_MONTH, -21); + String LOAN_DISBURSEMENT_DATE = dateFormat.format(todaysDate.getTime()); + final Integer loanID = applyForLoanApplication(clientID, loanProductID, LOAN_DISBURSEMENT_DATE); + Assert.assertNotNull(loanID); + HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID); + LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap); + + String guarantorJSON = new GuarantorTestBuilder().existingCustomerWithGuaranteeAmount(String.valueOf(clientID), + String.valueOf(selfSavigsId), String.valueOf(self1_guarantee)).build(); + Integer selfGuarantee = this.guarantorHelper.createGuarantor(loanID, guarantorJSON); + verifySavingsOnHoldBalance(selfSavigsId, null); + Assert.assertNotNull(selfGuarantee); + + guarantorJSON = new GuarantorTestBuilder().existingCustomerWithGuaranteeAmount(String.valueOf(clientID_external), + String.valueOf(externalSavigsId_1), String.valueOf(external1_guarantee)).build(); + Integer externalGuarantee_1 = this.guarantorHelper.createGuarantor(loanID, guarantorJSON); + Assert.assertNotNull(externalGuarantee_1); + verifySavingsOnHoldBalance(externalSavigsId_1, null); + + System.out.println("-----------------------------------APPROVE LOAN-----------------------------------------"); + loanStatusHashMap = this.loanTransactionHelper.approveLoan(LOAN_DISBURSEMENT_DATE, loanID); + LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); + LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap); + self1_hold_funds += self1_guarantee; + external1_hold_funds += external1_guarantee; + verifySavingsOnHoldBalance(selfSavigsId, self1_hold_funds); + verifySavingsOnHoldBalance(externalSavigsId_1, external1_hold_funds); + + System.out.println("-------------------------------DISBURSE LOAN-------------------------------------------"); + loanStatusHashMap = this.loanTransactionHelper.disburseLoan(LOAN_DISBURSEMENT_DATE, loanID); + LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap); + + // First repayment + ArrayList loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); + todaysDate = Calendar.getInstance(); + todaysDate.add(Calendar.DAY_OF_MONTH, -14); + String LOAN_REPAYMENT_DATE = dateFormat.format(todaysDate.getTime()); + Float totalDueForCurrentPeriod = (Float) loanSchedule.get(1).get("totalDueForPeriod"); + external1_hold_funds -= new Float(993.104); + this.loanTransactionHelper.makeRepayment(LOAN_REPAYMENT_DATE, totalDueForCurrentPeriod, loanID); + verifySavingsOnHoldBalance(selfSavigsId, self1_hold_funds); + verifySavingsOnHoldBalance(externalSavigsId_1, external1_hold_funds); + + todaysDate = Calendar.getInstance(); + String LOAN_WRITEOFF_DATE = dateFormat.format(todaysDate.getTime()); + this.loanTransactionHelper.writeOffLoan(LOAN_WRITEOFF_DATE, loanID); + verifySavingsBalanceAndOnHoldBalance(selfSavigsId, new Float(0), self1_balance); + verifySavingsBalanceAndOnHoldBalance(externalSavigsId_1, new Float(0), external1_balance); + + } + + private void verifySavingsOnHoldBalance(final Integer savingsId, final Float expectedBalance) { + Float onHoldAmount = (Float) this.savingsAccountHelper.getSavingsDetails(savingsId, "onHoldFunds"); + assertEquals("Verifying On Hold Funds", expectedBalance, onHoldAmount); + } + + @SuppressWarnings({ "rawtypes", "cast" }) + private void verifySavingsBalanceAndOnHoldBalance(final Integer savingsId, final Float expectedBalance, final Float accountBalance) { + HashMap savingsDetails = (HashMap) this.savingsAccountHelper.getSavingsDetails(savingsId); + assertEquals("Verifying On Hold Funds", expectedBalance, savingsDetails.get("onHoldFunds")); + HashMap summary = (HashMap) savingsDetails.get("summary"); + assertEquals("Verifying Account balance", accountBalance, summary.get("accountBalance")); + } + + @SuppressWarnings("rawtypes") + private boolean checkForErrorCode(final ArrayList errorData, final String errorcode) { + boolean isExists = false; + for (HashMap errorMap : errorData) { + String actualErrorCode = (String) errorMap.get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE); + if (actualErrorCode != null && actualErrorCode.equals(errorcode)) { + isExists = true; + break; + } + } + return isExists; + + } + + private Integer createLoanProductWithHoldFunds(final String mandatoryGuarantee, final String minimumGuaranteeFromGuarantor, + final String minimumGuaranteeFromOwnFunds) { + System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------"); + LoanProductTestBuilder builder = new LoanProductTestBuilder().withPrincipal("10000.00").withNumberOfRepayments("4") + .withRepaymentAfterEvery("1").withRepaymentTypeAsWeek().withinterestRatePerPeriod("2") + .withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsDecliningBalance() + .withOnHoldFundDetails(mandatoryGuarantee, minimumGuaranteeFromGuarantor, minimumGuaranteeFromOwnFunds); + + final String loanProductJSON = builder.build(null); + return this.loanTransactionHelper.getLoanProductId(loanProductJSON); + } + + private Integer applyForLoanApplication(final Integer clientID, final Integer loanProductID, final String disbursementDate) { + System.out.println("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------"); + final String loanApplicationJSON = new LoanApplicationTestBuilder() // + .withPrincipal("10000.00") // + .withLoanTermFrequency("4") // + .withLoanTermFrequencyAsWeeks() // + .withNumberOfRepayments("4") // + .withRepaymentEveryAfter("1") // + .withRepaymentFrequencyTypeAsWeeks() // + .withInterestRatePerPeriod("2") // + .withAmortizationTypeAsEqualInstallments() // + .withInterestTypeAsDecliningBalance() // + .withInterestCalculationPeriodTypeSameAsRepaymentPeriod() // + .withExpectedDisbursementDate(disbursementDate) // + .withSubmittedOnDate(disbursementDate) // + .build(clientID.toString(), loanProductID.toString(), null); + return this.loanTransactionHelper.getLoanId(loanApplicationJSON); + } + +} diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/loanaccount/guarantor/GuarantorTestBuilder.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/loanaccount/guarantor/GuarantorTestBuilder.java new file mode 100755 index 000000000..765b47362 --- /dev/null +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/loanaccount/guarantor/GuarantorTestBuilder.java @@ -0,0 +1,74 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.integrationtests.loanaccount.guarantor; + +import java.util.HashMap; + +import org.mifosplatform.integrationtests.common.Utils; + +import com.google.gson.Gson; + +public class GuarantorTestBuilder { + + private static final String GUARANTOR_TYPE_CUSTOMER = "1"; + @SuppressWarnings("unused") + private static final String GUARANTOR_TYPE_STAFF = "2"; + private static final String GUARANTOR_TYPE_EXTERNAL = "3"; + + private String guarantorTypeId = "1"; + private String entityId = null; + private String addressLine1 = "addressLine1"; + private String addressLine2 = "addressLine2"; + private String city = "city"; + private String state = "state"; + private String zip = "123456"; + private String guaranteeAmount = "500"; + private String savingsId = null; + + public String build() { + final HashMap map = new HashMap<>(); + map.put("guarantorTypeId", guarantorTypeId); + map.put("locale", "en"); + if (GUARANTOR_TYPE_EXTERNAL.equals(guarantorTypeId)) { + map.put("firstname", Utils.randomNameGenerator("guarantor_FirstName_", 5)); + map.put("lastname", Utils.randomNameGenerator("guarantor_LastName_", 4)); + map.put("addressLine1", addressLine1); + map.put("addressLine2", addressLine2); + map.put("city", city); + map.put("state", state); + map.put("zip", zip); + + } else if (GUARANTOR_TYPE_CUSTOMER.equals(guarantorTypeId)) { + map.put("entityId", entityId); + map.put("amount", guaranteeAmount); + map.put("savingsId", savingsId); + } + System.out.println("map : " + map); + return new Gson().toJson(map); + } + + public GuarantorTestBuilder existingCustomerWithGuaranteeAmount(final String entityId, final String savingsId, + final String guaranteeAmount) { + this.entityId = entityId; + this.savingsId = savingsId; + this.guaranteeAmount = guaranteeAmount; + this.guarantorTypeId = GUARANTOR_TYPE_CUSTOMER; + return this; + } + + public GuarantorTestBuilder existingCustomerWithoutGuaranteeAmount(final String entityId) { + this.entityId = entityId; + this.savingsId = null; + this.guaranteeAmount = null; + this.guarantorTypeId = GUARANTOR_TYPE_CUSTOMER; + return this; + } + + public GuarantorTestBuilder externalCustomer() { + this.guarantorTypeId = GUARANTOR_TYPE_EXTERNAL; + return this; + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/common/service/BusinessEventListner.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/common/service/BusinessEventListner.java index 569d7d2ab..ce2195a4e 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/common/service/BusinessEventListner.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/common/service/BusinessEventListner.java @@ -7,10 +7,22 @@ package org.mifosplatform.portfolio.common.service; import org.springframework.data.jpa.domain.AbstractPersistable; +/** + * The interface to be implemented by classes that want to be informed when a + * Business Event executes. example: on completion of loan approval event need + * to block guarantor funds + * + */ public interface BusinessEventListner { + /** + * Implement this method for notifications before executing Business Event + */ public void businessEventToBeExecuted(AbstractPersistable businessEventEntity); + /** + * Implement this method for notifications after executing Business Event + */ public void businessEventWasExecuted(AbstractPersistable businessEventEntity); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/common/service/BusinessEventNotifierService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/common/service/BusinessEventNotifierService.java index 47163b6e3..0fc55d1fd 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/common/service/BusinessEventNotifierService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/common/service/BusinessEventNotifierService.java @@ -8,14 +8,35 @@ package org.mifosplatform.portfolio.common.service; import org.mifosplatform.portfolio.common.BusinessEventNotificationConstants.BUSINESS_EVENTS; import org.springframework.data.jpa.domain.AbstractPersistable; +/** + * Implemented class is responsible for notifying the business event to + * registered listeners. + * + */ public interface BusinessEventNotifierService { + /** + * Method should be called to notify listeners before Business event + * execution for any pre-processing of event + */ public void notifyBusinessEventToBeExecuted(BUSINESS_EVENTS businessEvent, AbstractPersistable businessEventEntity); + /** + * Method should be called to notify listeners after Business event + * execution for any post-processing of event + */ public void notifyBusinessEventWasExecuted(BUSINESS_EVENTS businessEvent, AbstractPersistable businessEventEntity); + /** + * Method is to register a class as listener for pre-processing of any + * Business event + */ public void addBusinessEventPreListners(BUSINESS_EVENTS businessEvent, BusinessEventListner businessEventListner); + /** + * Method is to register a class as listener for post-processing of any + * Business event + */ public void addBusinessEventPostListners(BUSINESS_EVENTS businessEvent, BusinessEventListner businessEventListner); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/common/service/BusinessEventNotifierServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/common/service/BusinessEventNotifierServiceImpl.java index 83b06b256..53637b9ef 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/common/service/BusinessEventNotifierServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/common/service/BusinessEventNotifierServiceImpl.java @@ -20,6 +20,16 @@ public class BusinessEventNotifierServiceImpl implements BusinessEventNotifierSe private final Map> preListners = new HashMap<>(5); private final Map> postListners = new HashMap<>(5); + /* + * (non-Javadoc) + * + * @see + * org.mifosplatform.portfolio.common.service.BusinessEventNotifierService + * #notifyBusinessEventToBeExecuted + * (org.mifosplatform.portfolio.common.BusinessEventNotificationConstants + * .BUSINESS_EVENTS, + * org.springframework.data.jpa.domain.AbstractPersistable) + */ @Override public void notifyBusinessEventToBeExecuted(BUSINESS_EVENTS businessEvent, AbstractPersistable businessEventEntity) { List businessEventListners = this.preListners.get(businessEvent); @@ -30,6 +40,16 @@ public class BusinessEventNotifierServiceImpl implements BusinessEventNotifierSe } } + /* + * (non-Javadoc) + * + * @see + * org.mifosplatform.portfolio.common.service.BusinessEventNotifierService + * #notifyBusinessEventWasExecuted + * (org.mifosplatform.portfolio.common.BusinessEventNotificationConstants + * .BUSINESS_EVENTS, + * org.springframework.data.jpa.domain.AbstractPersistable) + */ @Override public void notifyBusinessEventWasExecuted(BUSINESS_EVENTS businessEvent, AbstractPersistable businessEventEntity) { List businessEventListners = this.postListners.get(businessEvent); @@ -40,11 +60,31 @@ public class BusinessEventNotifierServiceImpl implements BusinessEventNotifierSe } } + /* + * (non-Javadoc) + * + * @see + * org.mifosplatform.portfolio.common.service.BusinessEventNotifierService + * #addBusinessEventPreListners + * (org.mifosplatform.portfolio.common.BusinessEventNotificationConstants + * .BUSINESS_EVENTS, + * org.mifosplatform.portfolio.common.service.BusinessEventListner) + */ @Override public void addBusinessEventPreListners(BUSINESS_EVENTS businessEvent, BusinessEventListner businessEventListner) { addBusinessEventListners(businessEvent, businessEventListner, preListners); } + /* + * (non-Javadoc) + * + * @see + * org.mifosplatform.portfolio.common.service.BusinessEventNotifierService + * #addBusinessEventPostListners + * (org.mifosplatform.portfolio.common.BusinessEventNotificationConstants + * .BUSINESS_EVENTS, + * org.mifosplatform.portfolio.common.service.BusinessEventListner) + */ @Override public void addBusinessEventPostListners(BUSINESS_EVENTS businessEvent, BusinessEventListner businessEventListner) { addBusinessEventListners(businessEvent, businessEventListner, postListners); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/guarantor/service/GuarantorDomainServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/guarantor/service/GuarantorDomainServiceImpl.java index a224aba52..784834ac4 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/guarantor/service/GuarantorDomainServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/guarantor/service/GuarantorDomainServiceImpl.java @@ -146,6 +146,10 @@ public class GuarantorDomainServiceImpl implements GuarantorDomainService { } + /** + * Method assigns a guarantor to loan and blocks the funds on guarantor's + * account + */ @Override public void assignGuarantor(final GuarantorFundingDetails guarantorFundingDetails, final LocalDate transactionDate) { if (guarantorFundingDetails.getStatus().isActive()) { @@ -168,6 +172,10 @@ public class GuarantorDomainServiceImpl implements GuarantorDomainService { } } + /** + * Method releases(withdraw) a guarantor from loan and unblocks the funds on + * guarantor's account + */ @Override public void releaseGuarantor(final GuarantorFundingDetails guarantorFundingDetails, final LocalDate transactionDate) { BigDecimal amoutForWithdraw = guarantorFundingDetails.getAmountRemaining(); @@ -187,6 +195,11 @@ public class GuarantorDomainServiceImpl implements GuarantorDomainService { } } + /** + * Method is to recover funds from guarantor's in case loan is unpaid. + * (Transfers guarantee amount from guarantor's account to loan account and + * releases guarantor) + */ @Override public void transaferFundsFromGuarantor(final Loan loan) { if (loan.getGuaranteeAmount().compareTo(BigDecimal.ZERO) != 1) { return; } @@ -254,6 +267,11 @@ public class GuarantorDomainServiceImpl implements GuarantorDomainService { } } + /** + * Method reverses all blocked fund(both hold and release) transactions. + * example: reverses all transactions on undo approval of loan account. + * + */ private void reverseAllFundTransaction(final Loan loan) { if (loan.getGuaranteeAmount().compareTo(BigDecimal.ZERO) == 1) { @@ -274,6 +292,11 @@ public class GuarantorDomainServiceImpl implements GuarantorDomainService { } } + /** + * Method holds all guarantor's guarantee amount for a loan account. + * example: hold funds on approval of loan account. + * + */ private void holdGuarantorFunds(final Loan loan) { if (loan.loanProduct().isHoldGuaranteeFundsEnabled()) { final List existGuarantorList = this.guarantorRepository.findByLoan(loan); @@ -318,6 +341,13 @@ public class GuarantorDomainServiceImpl implements GuarantorDomainService { } } + /** + * Method releases all guarantor's guarantee amount(first external guarantee + * and then self guarantee) for a loan account in the portion of guarantee + * percentage on a paid principal. example: releases funds on repayments of + * loan account. + * + */ private void releaseGuarantorFunds(final LoanTransaction loanTransaction) { final Loan loan = loanTransaction.getLoan(); if (loan.getGuaranteeAmount().compareTo(BigDecimal.ZERO) == 1) { @@ -364,6 +394,11 @@ public class GuarantorDomainServiceImpl implements GuarantorDomainService { } + /** + * Method releases all guarantor's guarantee amount. example: releases funds + * on write-off of a loan account. + * + */ private void releaseAllGuarantors(final LoanTransaction loanTransaction) { Loan loan = loanTransaction.getLoan(); if (loan.getGuaranteeAmount().compareTo(BigDecimal.ZERO) == 1) { @@ -398,6 +433,11 @@ public class GuarantorDomainServiceImpl implements GuarantorDomainService { } } + /** + * Method releases guarantor's guarantee amount on transferring guarantee + * amount to loan account. example: on recovery of guarantee funds from + * guarantor's. + */ private void completeGuarantorFund(final LoanTransaction loanTransaction) { Loan loan = loanTransaction.getLoan(); GuarantorFundingDetails guarantorFundingDetails = this.guarantorFundingRepository.findOne(releaseLoanIds.get(loan.getId())); @@ -437,6 +477,10 @@ public class GuarantorDomainServiceImpl implements GuarantorDomainService { return amountLeft; } + /** + * Method reverses the fund release transactions in case of loan transaction + * reversed + */ private void reverseTransaction(final List loanTransactionIds) { List fundingTransactions = this.guarantorFundingTransactionRepository diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/guarantor/service/GuarantorWritePlatformServiceJpaRepositoryIImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/guarantor/service/GuarantorWritePlatformServiceJpaRepositoryIImpl.java index 706fd8565..6f89f313b 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/guarantor/service/GuarantorWritePlatformServiceJpaRepositoryIImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/guarantor/service/GuarantorWritePlatformServiceJpaRepositoryIImpl.java @@ -123,7 +123,7 @@ public class GuarantorWritePlatformServiceJpaRepositoryIImpl implements Guaranto final Integer guarantorTypeId = guarantorCommand.getGuarantorTypeId(); Guarantor guarantor = null; for (final Guarantor avilableGuarantor : existGuarantorList) { - if (entityId != null && avilableGuarantor.getEntityId() == entityId + if (entityId != null && avilableGuarantor.getEntityId() != null && avilableGuarantor.getEntityId().equals(entityId) && avilableGuarantor.getGurantorType() == guarantorTypeId && avilableGuarantor.isActive()) { if (guarantorCommand.getSavingsId() == null || avilableGuarantor.hasGuarantor(guarantorCommand.getSavingsId())) { /** Get the right guarantor based on guarantorType **/ @@ -251,15 +251,7 @@ public class GuarantorWritePlatformServiceJpaRepositoryIImpl implements Guaranto GuarantorFundingDetails guarantorFundingDetails = guarantorForDelete.getGuarantorFundingDetail(guarantorFundingId); if (guarantorFundingDetails == null) { throw new GuarantorNotFoundException(loanId, guarantorForDelete.getId(), guarantorFundingId); } - if (!guarantorFundingDetails.getStatus().isActive()) { - baseDataValidator.failWithCodeNoParameterAddedToErrorCode(GuarantorConstants.GUARANTOR_NOT_ACTIVE_ERROR); - } - GuarantorFundStatusType fundStatusType = GuarantorFundStatusType.DELETED; - if (guarantorForDelete.getLoan().isDisbursed() || guarantorForDelete.getLoan().isApproved()) { - fundStatusType = GuarantorFundStatusType.WITHDRAWN; - this.guarantorDomainService.releaseGuarantor(guarantorFundingDetails, LocalDate.now()); - } - guarantorForDelete.updateStatus(guarantorFundingDetails, fundStatusType); + removeguarantorFundDetails(guarantorForDelete, baseDataValidator, guarantorFundingDetails); } if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", @@ -274,6 +266,19 @@ public class GuarantorWritePlatformServiceJpaRepositoryIImpl implements Guaranto return commandProcessingResultBuilder.build(); } + private void removeguarantorFundDetails(final Guarantor guarantorForDelete, final DataValidatorBuilder baseDataValidator, + GuarantorFundingDetails guarantorFundingDetails) { + if (!guarantorFundingDetails.getStatus().isActive()) { + baseDataValidator.failWithCodeNoParameterAddedToErrorCode(GuarantorConstants.GUARANTOR_NOT_ACTIVE_ERROR); + } + GuarantorFundStatusType fundStatusType = GuarantorFundStatusType.DELETED; + if (guarantorForDelete.getLoan().isDisbursed() || guarantorForDelete.getLoan().isApproved()) { + fundStatusType = GuarantorFundStatusType.WITHDRAWN; + this.guarantorDomainService.releaseGuarantor(guarantorFundingDetails, LocalDate.now()); + } + guarantorForDelete.updateStatus(guarantorFundingDetails, fundStatusType); + } + private void validateGuarantorBusinessRules(final Guarantor guarantor) { // validate guarantor conditions if (guarantor.isExistingCustomer()) {