Skip to content

Commit 7d4df3d

Browse files
FINERACT-2476: Enable Group Savings Accounts as Guarantors with Guarantee Percentage Requirements
1 parent 6269cbb commit 7d4df3d

File tree

4 files changed

+78
-3
lines changed

4 files changed

+78
-3
lines changed

fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/guarantor/service/GuarantorDomainServiceImpl.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ public void validateGuarantorBusinessRules(Loan loan) {
116116
BigDecimal minSelfAmount = principal.multiply(guaranteeData.getMinimumGuaranteeFromOwnFunds()).divide(BigDecimal.valueOf(100));
117117
BigDecimal minExtGuarantee = principal.multiply(guaranteeData.getMinimumGuaranteeFromGuarantor())
118118
.divide(BigDecimal.valueOf(100));
119-
119+
boolean hasGroupSavingsAccountGuarantor = false;
120120
BigDecimal actualAmount = BigDecimal.ZERO;
121121
BigDecimal actualSelfAmount = BigDecimal.ZERO;
122122
BigDecimal actualExtGuarantee = BigDecimal.ZERO;
@@ -125,7 +125,12 @@ public void validateGuarantorBusinessRules(Loan loan) {
125125
for (GuarantorFundingDetails guarantorFundingDetails : fundingDetails) {
126126
if (guarantorFundingDetails.getStatus().isActive() || guarantorFundingDetails.getStatus().isWithdrawn()
127127
|| guarantorFundingDetails.getStatus().isCompleted()) {
128-
if (guarantor.isSelfGuarantee()) {
128+
SavingsAccount savingsAccount = guarantorFundingDetails.getLinkedSavingsAccount();
129+
if (savingsAccount.isGroupAccount()) {
130+
hasGroupSavingsAccountGuarantor = true;
131+
actualExtGuarantee = actualExtGuarantee.add(guarantorFundingDetails.getAmount())
132+
.subtract(guarantorFundingDetails.getAmountTransfered());
133+
} else if (guarantor.isSelfGuarantee()) {
129134
actualSelfAmount = actualSelfAmount.add(guarantorFundingDetails.getAmount())
130135
.subtract(guarantorFundingDetails.getAmountTransfered());
131136
} else {
@@ -138,7 +143,7 @@ public void validateGuarantorBusinessRules(Loan loan) {
138143

139144
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
140145
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan.guarantor");
141-
if (actualSelfAmount.compareTo(minSelfAmount) < 0) {
146+
if (!hasGroupSavingsAccountGuarantor && actualSelfAmount.compareTo(minSelfAmount) < 0) {
142147
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(GuarantorConstants.GUARANTOR_SELF_GUARANTEE_ERROR,
143148
minSelfAmount);
144149
}

fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3366,6 +3366,10 @@ public boolean isTransactionAllowed(SavingsAccountTransactionType transactionTyp
33663366
return !isAccountLocked(transactionDate);
33673367
}
33683368

3369+
public boolean isGroupAccount() {
3370+
return (this.getGroupId() != null);
3371+
}
3372+
33693373
public BigDecimal minBalanceForInterestCalculation() {
33703374
return this.minBalanceForInterestCalculation;
33713375
}

integration-tests/src/test/java/org/apache/fineract/integrationtests/common/savings/SavingsAccountHelper.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ public class SavingsAccountHelper {
107107
public static final String TRANSACTION_DATE_PLUS_ONE = "02 March 2013";
108108
public static final String LAST_TRANSACTION_DATE = "01 March 2013";
109109
public static final String ACCOUNT_TYPE_INDIVIDUAL = "INDIVIDUAL";
110+
public static final String ACCOUNT_TYPE_GROUP = "GROUP";
110111
public static final Long PAYMENT_TYPE_ID = 1L;
111112

112113
public static final String DATE_TIME_FORMAT = "dd MMMM yyyy HH:mm";
@@ -1293,6 +1294,31 @@ public static Integer openSavingsAccount(final RequestSpecification requestSpec,
12931294
return savingsId;
12941295
}
12951296

1297+
// TODO: Rewrite to use fineract-client instead!
1298+
// Example: org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper.disburseLoan(java.lang.Long,
1299+
// org.apache.fineract.client.models.PostLoansLoanIdRequest)
1300+
@Deprecated(forRemoval = true)
1301+
public static Integer openGroupSavingsAccount(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
1302+
final Integer groupId, final String minimumOpeningBalance) {
1303+
final Integer savingsProductID = createSavingsProduct(requestSpec, responseSpec, minimumOpeningBalance);
1304+
Assertions.assertNotNull(savingsProductID);
1305+
1306+
SavingsAccountHelper savingsAccountHelper = new SavingsAccountHelper(requestSpec, responseSpec);
1307+
1308+
final Integer savingsId = savingsAccountHelper.applyForSavingsApplication(groupId, savingsProductID, ACCOUNT_TYPE_GROUP);
1309+
Assertions.assertNotNull(savingsProductID);
1310+
1311+
HashMap savingsStatusHashMap = SavingsStatusChecker.getStatusOfSavings(requestSpec, responseSpec, savingsId);
1312+
SavingsStatusChecker.verifySavingsIsPending(savingsStatusHashMap);
1313+
1314+
savingsStatusHashMap = savingsAccountHelper.approveSavings(savingsId);
1315+
SavingsStatusChecker.verifySavingsIsApproved(savingsStatusHashMap);
1316+
1317+
savingsStatusHashMap = savingsAccountHelper.activateSavings(savingsId);
1318+
SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap);
1319+
return savingsId;
1320+
}
1321+
12961322
// TODO: Rewrite to use fineract-client instead!
12971323
// Example: org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper.disburseLoan(java.lang.Long,
12981324
// org.apache.fineract.client.models.PostLoansLoanIdRequest)

integration-tests/src/test/java/org/apache/fineract/integrationtests/guarantor/GuarantorTest.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.apache.fineract.integrationtests.common.ClientHelper;
4040
import org.apache.fineract.integrationtests.common.CollateralManagementHelper;
4141
import org.apache.fineract.integrationtests.common.CommonConstants;
42+
import org.apache.fineract.integrationtests.common.GroupHelper;
4243
import org.apache.fineract.integrationtests.common.Utils;
4344
import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder;
4445
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
@@ -238,6 +239,45 @@ public void testGuarantor() {
238239

239240
}
240241

242+
@SuppressWarnings({ "rawtypes", "unchecked" })
243+
@Test
244+
public void testGuarantor_GROUP_SAVINGS_ACCOUNT_WITH_NON_ZERO_GUARANTEE() {
245+
Float group_hold_funds = Float.valueOf((float) 0);
246+
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
247+
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
248+
249+
final Integer groupId = GroupHelper.createGroup(this.requestSpec, this.responseSpec, true);
250+
GroupHelper.associateClient(this.requestSpec, this.responseSpec, groupId.toString(), clientID.toString());
251+
252+
final Integer groupSavingsId = SavingsAccountHelper.openGroupSavingsAccount(this.requestSpec, this.responseSpec, groupId, "10000");
253+
254+
final Integer loanProductID = createLoanProductWithHoldFunds("20", "10", "10");
255+
DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy", Locale.US);
256+
Calendar todaysDate = Calendar.getInstance();
257+
todaysDate.add(Calendar.DAY_OF_MONTH, -7 * 4);
258+
final String loanDisbursementDate = dateFormat.format(todaysDate.getTime());
259+
final Integer loanID = applyForLoanApplication(clientID, loanProductID, loanDisbursementDate);
260+
Assertions.assertNotNull(loanID);
261+
262+
ArrayList<HashMap> errorData = (ArrayList<HashMap>) this.loanTransactionHelper.approveLoan(loanDisbursementDate, null, loanID,
263+
CommonConstants.RESPONSE_ERROR);
264+
assertTrue(checkForErrorCode(errorData, "validation.msg.loan.guarantor.min.self.guarantee.required"));
265+
assertTrue(checkForErrorCode(errorData, "validation.msg.loan.guarantor.min.external.guarantee.required"));
266+
assertTrue(checkForErrorCode(errorData, "validation.msg.loan.guarantor.mandated.guarantee.required"));
267+
268+
String guarantorJSON = new GuarantorTestBuilder()
269+
.existingCustomerWithGuaranteeAmount(String.valueOf(clientID), String.valueOf(groupSavingsId), "2500").build();
270+
Integer groupGuarantee = this.guarantorHelper.createGuarantor(loanID, guarantorJSON);
271+
Assertions.assertNotNull(groupGuarantee);
272+
verifySavingsOnHoldBalance(groupSavingsId, null);
273+
LOG.info("-----------------------------------APPROVE LOAN-----------------------------------------");
274+
HashMap loanStatusHashMap = this.loanTransactionHelper.approveLoan(loanDisbursementDate, loanID);
275+
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
276+
LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap);
277+
group_hold_funds += Float.valueOf((float) 2500);
278+
verifySavingsOnHoldBalance(groupSavingsId, group_hold_funds);
279+
}
280+
241281
@SuppressWarnings({ "rawtypes", "unchecked" })
242282
@Test
243283
public void testGuarantor_UNDO_DISBURSAL() {

0 commit comments

Comments
 (0)