FINERACT-1954: Waive null pointer and due date fix
- [x] Fix Waive due date handle - [x] Fix null pointer exception - [x] Integration test
This commit is contained in:
+6
-1
@@ -1081,7 +1081,12 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
transactionDate = loanCharge.getDueLocalDate();
|
||||
}
|
||||
} else if (loanCharge.isInstalmentFee()) {
|
||||
transactionDate = loanCharge.getInstallmentLoanCharge(loanInstallmentNumber).getRepaymentInstallment().getDueDate();
|
||||
LocalDate repaymentDueDate = loanCharge.getInstallmentLoanCharge(loanInstallmentNumber).getRepaymentInstallment().getDueDate();
|
||||
if (repaymentDueDate.isAfter(DateUtils.getBusinessLocalDate())) {
|
||||
transactionDate = DateUtils.getBusinessLocalDate();
|
||||
} else {
|
||||
transactionDate = repaymentDueDate;
|
||||
}
|
||||
}
|
||||
|
||||
scheduleGeneratorDTO.setRecalculateFrom(transactionDate);
|
||||
|
||||
+2
-1
@@ -25,6 +25,7 @@ import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import java.math.BigDecimal;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.interoperation.util.MathUtil;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanInstallmentChargeData;
|
||||
@@ -168,7 +169,7 @@ public class LoanInstallmentCharge extends AbstractPersistableCustom implements
|
||||
}
|
||||
|
||||
public boolean isPending() {
|
||||
return !(isPaid() || isWaived());
|
||||
return !MathUtil.isZero(this.amountOutstanding);
|
||||
}
|
||||
|
||||
public boolean isChargeAmountpaid(MonetaryCurrency currency) {
|
||||
|
||||
-1
@@ -209,7 +209,6 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
}
|
||||
}
|
||||
reprocessInstallments(installments, currency);
|
||||
|
||||
return changedTransactionDetail;
|
||||
}
|
||||
|
||||
|
||||
+151
@@ -20,6 +20,7 @@ package org.apache.fineract.integrationtests;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import io.restassured.builder.RequestSpecBuilder;
|
||||
import io.restassured.builder.ResponseSpecBuilder;
|
||||
@@ -30,10 +31,12 @@ import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.client.models.GetJournalEntriesTransactionIdResponse;
|
||||
import org.apache.fineract.client.models.GetLoanProductsProductIdResponse;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdTransactions;
|
||||
import org.apache.fineract.client.models.JournalEntryTransactionItem;
|
||||
import org.apache.fineract.client.models.PostChargesResponse;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdChargesChargeIdResponse;
|
||||
@@ -233,6 +236,154 @@ public class LoanChargeSpecificDueDateTest {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyAndWaiveInstallmentFee() {
|
||||
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
|
||||
final LocalDate todaysDate = Utils.getLocalDateOfTenant();
|
||||
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, todaysDate);
|
||||
|
||||
// Client and Loan account creation
|
||||
final Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2012");
|
||||
final GetLoanProductsProductIdResponse getLoanProductsProductResponse = createLoanProduct(loanTransactionHelper, null);
|
||||
assertNotNull(getLoanProductsProductResponse);
|
||||
|
||||
// Older date to have more than one overdue installment
|
||||
LocalDate transactionDate = todaysDate;
|
||||
String operationDate = Utils.dateFormatter.format(transactionDate);
|
||||
log.info("Operation date {}", transactionDate);
|
||||
|
||||
// Create Loan Account
|
||||
final Integer loanId = createLoanAccount(loanTransactionHelper, clientId.toString(),
|
||||
getLoanProductsProductResponse.getId().toString(), operationDate, "1", "0");
|
||||
|
||||
// Get loan details
|
||||
GetLoansLoanIdResponse getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
validateLoanAccount(getLoansLoanIdResponse, Double.valueOf(principalAmount), Double.valueOf("0.00"), false);
|
||||
|
||||
// Apply Loan Charge with specific due date
|
||||
final String feeAmount = "1.500000";
|
||||
String payloadJSON = ChargesHelper.getLoanSpecificInstallmentFeeJSON();
|
||||
final PostChargesResponse postChargesResponse = ChargesHelper.createLoanCharge(requestSpec, responseSpec, payloadJSON);
|
||||
assertNotNull(postChargesResponse);
|
||||
final Long chargeId = postChargesResponse.getResourceId();
|
||||
assertNotNull(chargeId);
|
||||
|
||||
float amount = Float.parseFloat("5.00");
|
||||
PostLoansLoanIdTransactionsResponse loanIdTransactionsResponse = loanTransactionHelper.makeLoanRepayment(operationDate, amount,
|
||||
loanId);
|
||||
|
||||
payloadJSON = LoanTransactionHelper.getSpecifiedInstallmentChargesForLoanAsJSON(chargeId.toString(), feeAmount);
|
||||
PostLoansLoanIdChargesResponse postLoansLoanIdChargesResponse = loanTransactionHelper.addChargeForLoan(loanId, payloadJSON,
|
||||
responseSpec);
|
||||
assertNotNull(postLoansLoanIdChargesResponse);
|
||||
final Long loanChargeId = postLoansLoanIdChargesResponse.getResourceId();
|
||||
assertNotNull(loanChargeId);
|
||||
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
validateLoanAccount(getLoansLoanIdResponse, Double.valueOf(principalAmount), Double.valueOf("10.00"), false);
|
||||
|
||||
// Waive the Loan Charge
|
||||
final PostLoansLoanIdChargesChargeIdResponse postWaiveLoanChargesResponse = loanTransactionHelper.applyLoanChargeCommand(loanId,
|
||||
loanChargeId, "waive", Utils.emptyJson());
|
||||
assertNotNull(postWaiveLoanChargesResponse);
|
||||
|
||||
// evaluate the outstanding
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
validateLoanAccount(getLoansLoanIdResponse, Double.valueOf(principalAmount), Double.valueOf("0.00"), false);
|
||||
|
||||
Optional<GetLoansLoanIdTransactions> waiveTransaction = getLoansLoanIdResponse.getTransactions().stream()
|
||||
.filter(transaction -> transaction.getType().getWaiveCharges() != null && transaction.getType().getWaiveCharges())
|
||||
.findFirst();
|
||||
assertTrue(waiveTransaction.isPresent());
|
||||
assertEquals(transactionDate, waiveTransaction.get().getDate());
|
||||
|
||||
// Make a full repayment to close the Loan
|
||||
amount = Float.parseFloat("1000.00");
|
||||
loanIdTransactionsResponse = loanTransactionHelper.makeLoanRepayment(operationDate, amount, loanId);
|
||||
assertNotNull(loanIdTransactionsResponse);
|
||||
log.info("Loan Transaction Id: {} {}", loanId, loanIdTransactionsResponse.getResourceId());
|
||||
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
assertNotNull(getLoansLoanIdResponse);
|
||||
loanTransactionHelper.validateLoanStatus(getLoansLoanIdResponse, "loanStatusType.closed.obligations.met");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyAndWaiveInstallmentFeeAnotherDueDate() {
|
||||
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
|
||||
final LocalDate todaysDate = Utils.getLocalDateOfTenant();
|
||||
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, todaysDate);
|
||||
|
||||
// Client and Loan account creation
|
||||
final Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2012");
|
||||
final GetLoanProductsProductIdResponse getLoanProductsProductResponse = createLoanProduct(loanTransactionHelper, null);
|
||||
assertNotNull(getLoanProductsProductResponse);
|
||||
|
||||
// Older date to have more than one overdue installment
|
||||
LocalDate transactionDate = todaysDate;
|
||||
String operationDate = Utils.dateFormatter.format(transactionDate);
|
||||
log.info("Operation date {}", transactionDate);
|
||||
|
||||
// Create Loan Account
|
||||
final Integer loanId = createLoanAccount(loanTransactionHelper, clientId.toString(),
|
||||
getLoanProductsProductResponse.getId().toString(), operationDate, "1", "0");
|
||||
|
||||
// Get loan details
|
||||
GetLoansLoanIdResponse getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
validateLoanAccount(getLoansLoanIdResponse, Double.valueOf(principalAmount), Double.valueOf("0.00"), false);
|
||||
|
||||
// Apply Loan Charge with specific due date
|
||||
final String feeAmount = "1.500000";
|
||||
String payloadJSON = ChargesHelper.getLoanSpecificInstallmentFeeJSON();
|
||||
final PostChargesResponse postChargesResponse = ChargesHelper.createLoanCharge(requestSpec, responseSpec, payloadJSON);
|
||||
assertNotNull(postChargesResponse);
|
||||
final Long chargeId = postChargesResponse.getResourceId();
|
||||
assertNotNull(chargeId);
|
||||
|
||||
float amount = Float.parseFloat("5.00");
|
||||
PostLoansLoanIdTransactionsResponse loanIdTransactionsResponse = loanTransactionHelper.makeLoanRepayment(operationDate, amount,
|
||||
loanId);
|
||||
transactionDate = todaysDate.plusDays(32);
|
||||
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, transactionDate);
|
||||
|
||||
payloadJSON = LoanTransactionHelper.getSpecifiedInstallmentChargesForLoanAsJSON(chargeId.toString(), feeAmount);
|
||||
PostLoansLoanIdChargesResponse postLoansLoanIdChargesResponse = loanTransactionHelper.addChargeForLoan(loanId, payloadJSON,
|
||||
responseSpec);
|
||||
assertNotNull(postLoansLoanIdChargesResponse);
|
||||
final Long loanChargeId = postLoansLoanIdChargesResponse.getResourceId();
|
||||
assertNotNull(loanChargeId);
|
||||
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
validateLoanAccount(getLoansLoanIdResponse, Double.valueOf(principalAmount), Double.valueOf("10.00"), false);
|
||||
LocalDate repaymentDueDate = getLoansLoanIdResponse.getRepaymentSchedule().getPeriods().get(1).getDueDate();
|
||||
// Waive the Loan Charge
|
||||
final PostLoansLoanIdChargesChargeIdResponse postWaiveLoanChargesResponse = loanTransactionHelper.applyLoanChargeCommand(loanId,
|
||||
loanChargeId, "waive", Utils.emptyJson());
|
||||
assertNotNull(postWaiveLoanChargesResponse);
|
||||
|
||||
// evaluate the outstanding
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
validateLoanAccount(getLoansLoanIdResponse, Double.valueOf(principalAmount), Double.valueOf("0.00"), false);
|
||||
|
||||
Optional<GetLoansLoanIdTransactions> waiveTransaction = getLoansLoanIdResponse.getTransactions().stream()
|
||||
.filter(transaction -> transaction.getType().getWaiveCharges() != null && transaction.getType().getWaiveCharges())
|
||||
.findFirst();
|
||||
assertTrue(waiveTransaction.isPresent());
|
||||
assertEquals(repaymentDueDate, waiveTransaction.get().getDate());
|
||||
|
||||
// Make a full repayment to close the Loan
|
||||
amount = Float.parseFloat("1000.00");
|
||||
loanIdTransactionsResponse = loanTransactionHelper.makeLoanRepayment(operationDate, amount, loanId);
|
||||
assertNotNull(loanIdTransactionsResponse);
|
||||
log.info("Loan Transaction Id: {} {}", loanId, loanIdTransactionsResponse.getResourceId());
|
||||
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
assertNotNull(getLoansLoanIdResponse);
|
||||
loanTransactionHelper.validateLoanStatus(getLoansLoanIdResponse, "loanStatusType.closed.obligations.met");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyAndWaiveLoanSpecificDueDatePenaltyWithDisbursementDate() {
|
||||
|
||||
|
||||
+23
@@ -237,6 +237,19 @@ public final class ChargesHelper extends IntegrationTest {
|
||||
return chargesCreateJson;
|
||||
}
|
||||
|
||||
public static String getLoanSpecificInstallmentFeeJSON() {
|
||||
final HashMap<String, Object> map = populateDefaultsForLoan();
|
||||
map.put("chargeTimeType", CHARGE_INSTALLMENT_FEE);
|
||||
map.put("chargePaymentMode", CHARGE_PAYMENT_MODE_REGULAR);
|
||||
map.put("penalty", false);
|
||||
map.put("amount", "1.500000");
|
||||
map.put("chargeCalculationType", CHARGE_CALCULATION_TYPE_PERCENTAGE_AMOUNT_AND_INTEREST);
|
||||
|
||||
String chargesCreateJson = new Gson().toJson(map);
|
||||
LOG.info("{}", chargesCreateJson);
|
||||
return chargesCreateJson;
|
||||
}
|
||||
|
||||
public static String getLoanSpecifiedDueDateWithAccountTransferJSON(final Integer chargeCalculationType, final String amount,
|
||||
boolean penalty) {
|
||||
return getLoanSpecifiedDueDateJSON(chargeCalculationType, amount, penalty, ChargesHelper.CHARGE_PAYMENT_MODE_ACCOUNT_TRANSFER);
|
||||
@@ -251,6 +264,16 @@ public final class ChargesHelper extends IntegrationTest {
|
||||
return getLoanInstallmentJSON(chargeCalculationType, amount, penalty, ChargesHelper.CHARGE_PAYMENT_MODE_REGULAR);
|
||||
}
|
||||
|
||||
public static String getLoanOverdueInstallmentJSON(final String amount) {
|
||||
final HashMap<String, Object> map = populateDefaultsForLoan();
|
||||
map.put("chargeId", CHARGE_OVERDUE_INSTALLMENT_FEE);
|
||||
map.put("amount", amount);
|
||||
|
||||
String chargesCreateJson = new Gson().toJson(map);
|
||||
LOG.info("{}", chargesCreateJson);
|
||||
return chargesCreateJson;
|
||||
}
|
||||
|
||||
public static String getLoanInstallmentJSON(final Integer chargeCalculationType, final String amount, final boolean penalty,
|
||||
final Integer paymentMode) {
|
||||
final HashMap<String, Object> map = populateDefaultsForLoan();
|
||||
|
||||
+11
@@ -1206,6 +1206,17 @@ public class LoanTransactionHelper extends IntegrationTest {
|
||||
return json;
|
||||
}
|
||||
|
||||
public static String getSpecifiedInstallmentChargesForLoanAsJSON(final String chargeId, final String amount) {
|
||||
final HashMap<String, String> map = new HashMap<>();
|
||||
map.put("locale", "en_GB");
|
||||
map.put("dateFormat", "dd MMMM yyyy");
|
||||
map.put("amount", amount);
|
||||
map.put("chargeId", chargeId);
|
||||
String json = new Gson().toJson(map);
|
||||
log.info("{}", json);
|
||||
return json;
|
||||
}
|
||||
|
||||
public static String getDisbursementChargesForLoanAsJSON(final String chargeId) {
|
||||
return getDisbursementChargesForLoanAsJSON(chargeId, "100");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user