FINERACT-1760: Fix error handling for loan charge details

This commit is contained in:
Adam Saghy
2022-12-01 22:51:19 +01:00
committed by Arnold Gálovics
parent de0910f337
commit 0162ffe1ea
4 changed files with 106 additions and 117 deletions
@@ -22,6 +22,7 @@ import org.apache.commons.lang3.ObjectUtils;
import org.apache.fineract.infrastructure.core.domain.ExternalId;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
import org.springframework.dao.EmptyResultDataAccessException;
/**
* {@link AbstractPlatformDomainRuleException} thrown when loan charge does not exist.
@@ -41,6 +42,11 @@ public class LoanChargeNotFoundException extends AbstractPlatformResourceNotFoun
id, loanId);
}
public LoanChargeNotFoundException(final Long id, final Long loanId, final EmptyResultDataAccessException e) {
super("error.msg.loanCharge.id.invalid.for.given.loan", "Loan charge with identifier " + id + " does not exist for loan " + loanId,
id, loanId, e);
}
public LoanChargeNotFoundException(ExternalId externalId) {
super("error.msg.loanCharge.external.id.invalid", "Loan Charge with external identifier "
+ ObjectUtils.defaultIfNull(externalId, ExternalId.empty()).getValue() + " does not exist", externalId);
@@ -36,6 +36,7 @@ import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.portfolio.charge.data.ChargeData;
import org.apache.fineract.portfolio.charge.domain.Charge;
import org.apache.fineract.portfolio.charge.exception.LoanChargeNotFoundException;
import org.apache.fineract.portfolio.charge.service.ChargeDropdownReadPlatformService;
import org.apache.fineract.portfolio.charge.service.ChargeEnumerations;
import org.apache.fineract.portfolio.common.service.DropdownReadPlatformService;
@@ -47,6 +48,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeRepository;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
import org.apache.fineract.portfolio.tax.data.TaxGroupData;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
@@ -169,20 +171,20 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
@Override
public LoanChargeData retrieveLoanChargeDetails(final Long id, final Long loanId) {
final LoanChargeMapper rm = new LoanChargeMapper();
final String sql = "select " + rm.schema() + " where lc.id=? and lc.loan_id=?";
return this.jdbcTemplate.queryForObject(sql, rm, id, loanId); // NOSONAR
try {
final LoanChargeMapper rm = new LoanChargeMapper();
final String sql = "select " + rm.schema() + " where lc.id=? and lc.loan_id=?";
return this.jdbcTemplate.queryForObject(sql, rm, id, loanId); // NOSONAR
} catch (final EmptyResultDataAccessException e) {
throw new LoanChargeNotFoundException(id, loanId, e);
}
}
@Override
public Collection<LoanChargeData> retrieveLoanCharges(final Long loanId) {
final LoanChargeMapper rm = new LoanChargeMapper();
final String sql = "select " + rm.schema() + " where lc.loan_id=? AND lc.is_active = true"
+ " order by coalesce(lc.due_for_collection_as_of_date,date(coalesce(dd.disbursedon_date,dd.expected_disburse_date))),lc.charge_time_enum ASC, lc.due_for_collection_as_of_date ASC, lc.is_penalty ASC";
return this.jdbcTemplate.query(sql, rm, loanId); // NOSONAR
}
@@ -700,6 +700,23 @@ public class ExternalIdSupportIntegrationTest extends IntegrationTest {
// Check whether the provided external id was retrieved
assertEquals(txnExternalIdStr, disbursedLoanResult.get("resourceExternalId"));
// Second loan
final HashMap loan2 = applyForLoanApplication(client.getClientId().intValue(), loanProductID, null);
Integer loan2Id = (Integer) loan2.get("resourceId");
this.loanTransactionHelper.approveLoan("02 September 2022", loan2Id);
final HashMap disbursedLoan2Result = this.loanTransactionHelper.disburseLoan("03 September 2022", loan2Id, "1000", null);
Integer penalty = ChargesHelper.createCharges(requestSpec, responseSpec,
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, "10", true));
LocalDate targetDate = LocalDate.of(2022, 9, 7);
final String penaltyCharge1AddedDate = dateFormatter.format(targetDate);
String penalty1LoanChargeExternalId = UUID.randomUUID().toString();
Integer penalty1LoanChargeId = this.loanTransactionHelper.addChargesForLoan(loan2Id,
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(penalty), penaltyCharge1AddedDate, "10",
penalty1LoanChargeExternalId));
// NEGATIVE SCENARIOS
// GET
@@ -762,6 +779,16 @@ public class ExternalIdSupportIntegrationTest extends IntegrationTest {
assertEquals(404, exception.getResponse().code());
assertTrue(exception.getMessage().contains("error.msg.loan.external.id.invalid"));
exception = assertThrows(CallFailedRuntimeException.class,
() -> this.loanTransactionHelper.getLoanCharge(-1L, (long) penalty1LoanChargeId));
assertEquals(404, exception.getResponse().code());
assertTrue(exception.getMessage().contains("error.msg.loanCharge.id.invalid.for.given.loan"));
exception = assertThrows(CallFailedRuntimeException.class,
() -> this.loanTransactionHelper.getLoanCharge(loanExternalIdStr, (long) penalty1LoanChargeId));
assertEquals(404, exception.getResponse().code());
assertTrue(exception.getMessage().contains("error.msg.loanCharge.id.invalid.for.given.loan"));
exception = assertThrows(CallFailedRuntimeException.class,
() -> this.loanTransactionHelper.getLoanCharge(loanExternalIdStr, "randomNonExistingLoanChargeExternalId"));
assertEquals(404, exception.getResponse().code());
@@ -18,6 +18,7 @@
*/
package org.apache.fineract.integrationtests;
import static java.time.temporal.ChronoUnit.DAYS;
import static org.junit.jupiter.api.Assertions.assertEquals;
import com.google.common.truth.Truth;
@@ -31,7 +32,6 @@ import java.math.RoundingMode;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoUnit;
@@ -1341,7 +1341,7 @@ public class FixedDepositTest {
todaysDate = todaysDate.minusMonths(1);
todaysDate = todaysDate.minusDays(1);
Float interestPerMonth = (float) (interestPerDay * principal * ChronoUnit.DAYS.between(todaysDate, Utils.getLocalDateOfTenant()));
Float interestPerMonth = (float) (interestPerDay * principal * DAYS.between(todaysDate, Utils.getLocalDateOfTenant()));
principal += interestPerMonth;
log.info("{}", Utils.dateFormatter.format(todaysDate));
log.info("IPM = {}", interestPerMonth);
@@ -1441,26 +1441,25 @@ public class FixedDepositTest {
this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec);
this.fixedDepositAccountHelper = new FixedDepositAccountHelper(this.requestSpec, this.responseSpec);
DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy", Locale.US);
DateFormat monthDayFormat = new SimpleDateFormat("dd MMM", Locale.US);
DateFormat currentDateFormat = new SimpleDateFormat("dd");
DateTimeFormatter dateFormat = new DateTimeFormatterBuilder().appendPattern("dd MMMM yyyy").toFormatter();
Calendar todaysDate = Calendar.getInstance();
todaysDate.add(Calendar.MONTH, -3);
final String VALID_FROM = dateFormat.format(todaysDate.getTime());
todaysDate.add(Calendar.YEAR, 10);
final String VALID_TO = dateFormat.format(todaysDate.getTime());
LocalDate todaysDate = Utils.getLocalDateOfTenant();
todaysDate = todaysDate.minusMonths(3);
final String VALID_FROM = dateFormat.format(todaysDate);
todaysDate = todaysDate.plusYears(10);
final String VALID_TO = dateFormat.format(todaysDate);
todaysDate = Calendar.getInstance();
todaysDate.add(Calendar.MONTH, -1);
todaysDate.add(Calendar.DAY_OF_MONTH, -1);
final String SUBMITTED_ON_DATE = dateFormat.format(todaysDate.getTime());
final String APPROVED_ON_DATE = dateFormat.format(todaysDate.getTime());
final String ACTIVATION_DATE = dateFormat.format(todaysDate.getTime());
monthDayFormat.format(todaysDate.getTime());
todaysDate.add(Calendar.MONTH, 1);
todaysDate.add(Calendar.DAY_OF_MONTH, 1);
final String CLOSED_ON_DATE = dateFormat.format(todaysDate.getTime());
todaysDate = Utils.getLocalDateOfTenant();
todaysDate = todaysDate.minusMonths(1);
todaysDate = todaysDate.minusDays(1);
final String SUBMITTED_ON_DATE = dateFormat.format(todaysDate);
final String APPROVED_ON_DATE = dateFormat.format(todaysDate);
final String ACTIVATION_DATE = dateFormat.format(todaysDate);
LocalDate activationDate = todaysDate;
todaysDate = todaysDate.plusMonths(1);
todaysDate = todaysDate.plusDays(1);
final String CLOSED_ON_DATE = dateFormat.format(todaysDate);
LocalDate closingDate = todaysDate;
Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec);
Assertions.assertNotNull(clientId);
@@ -1500,18 +1499,9 @@ public class FixedDepositTest {
log.info("per day = {}", perDay);
double interestPerDay = interestRateInFraction * perDay;
todaysDate.add(Calendar.MONTH, -1);
todaysDate.add(Calendar.DAY_OF_MONTH, -1);
Integer currentDate = Integer.valueOf(currentDateFormat.format(todaysDate.getTime()));
Integer daysInMonth = todaysDate.getActualMaximum(Calendar.DATE);
daysInMonth = daysInMonth - currentDate + 1;
Float interestPerMonth = (float) (interestPerDay * principal * daysInMonth);
principal += interestPerMonth;
todaysDate.add(Calendar.DATE, daysInMonth);
log.info("{}", monthDayFormat.format(todaysDate.getTime()));
interestPerMonth = (float) (interestPerDay * principal * currentDate);
log.info("IPM = {}", interestPerMonth);
principal += interestPerMonth;
long daysBetween = DAYS.between(activationDate, closingDate);
Float totalInterest = (float) (interestPerDay * principal * daysBetween);
principal += totalInterest;
log.info("principal = {}", principal);
this.fixedDepositAccountHelper.calculatePrematureAmountForFixedDeposit(fixedDepositAccountId, CLOSED_ON_DATE);
@@ -1540,26 +1530,25 @@ public class FixedDepositTest {
this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec);
this.fixedDepositAccountHelper = new FixedDepositAccountHelper(this.requestSpec, this.responseSpec);
DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy", Locale.US);
DateFormat monthDayFormat = new SimpleDateFormat("dd MMM", Locale.US);
DateFormat currentDateFormat = new SimpleDateFormat("dd");
DateTimeFormatter dateFormat = new DateTimeFormatterBuilder().appendPattern("dd MMMM yyyy").toFormatter();
Calendar todaysDate = Calendar.getInstance();
todaysDate.add(Calendar.MONTH, -3);
final String VALID_FROM = dateFormat.format(todaysDate.getTime());
todaysDate.add(Calendar.YEAR, 10);
final String VALID_TO = dateFormat.format(todaysDate.getTime());
LocalDate todaysDate = Utils.getLocalDateOfTenant().minusDays(32);
todaysDate = todaysDate.minusMonths(3);
final String VALID_FROM = dateFormat.format(todaysDate);
todaysDate = todaysDate.plusYears(10);
final String VALID_TO = dateFormat.format(todaysDate);
todaysDate = Calendar.getInstance();
todaysDate.add(Calendar.MONTH, -1);
todaysDate.add(Calendar.DAY_OF_MONTH, -1);
final String SUBMITTED_ON_DATE = dateFormat.format(todaysDate.getTime());
final String APPROVED_ON_DATE = dateFormat.format(todaysDate.getTime());
final String ACTIVATION_DATE = dateFormat.format(todaysDate.getTime());
monthDayFormat.format(todaysDate.getTime());
todaysDate.add(Calendar.MONTH, 1);
todaysDate.add(Calendar.DAY_OF_MONTH, 1);
final String CLOSED_ON_DATE = dateFormat.format(todaysDate.getTime());
todaysDate = Utils.getLocalDateOfTenant().minusDays(32);
todaysDate = todaysDate.minusMonths(1);
todaysDate = todaysDate.minusDays(1);
final String SUBMITTED_ON_DATE = dateFormat.format(todaysDate);
final String APPROVED_ON_DATE = dateFormat.format(todaysDate);
final String ACTIVATION_DATE = dateFormat.format(todaysDate);
LocalDate activationDate = todaysDate;
todaysDate = Utils.getLocalDateOfTenant();
final String CLOSED_ON_DATE = dateFormat.format(todaysDate);
LocalDate closingDate = todaysDate;
Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec);
Assertions.assertNotNull(clientId);
@@ -1591,15 +1580,7 @@ public class FixedDepositTest {
ArrayList<ArrayList<HashMap>> interestRateChartData = FixedDepositProductHelper
.getInterestRateChartSlabsByProductId(this.requestSpec, this.responseSpec, fixedDepositProductId);
Calendar activationDate = Calendar.getInstance();
activationDate.add(Calendar.MONTH, -1);
activationDate.add(Calendar.DAY_OF_MONTH, -1);
ZonedDateTime startDate = ZonedDateTime.ofInstant(activationDate.getTime().toInstant(), this.systemTimeZone.toZoneId());
Calendar prematureClosureDate = Calendar.getInstance();
ZonedDateTime endDate = ZonedDateTime.ofInstant(prematureClosureDate.getTime().toInstant(), this.systemTimeZone.toZoneId());
Integer depositedPeriod = Math.toIntExact(ChronoUnit.MONTHS.between(startDate.toLocalDate(), endDate.toLocalDate()));
Integer depositedPeriod = Math.toIntExact(ChronoUnit.MONTHS.between(activationDate, closingDate));
Float interestRate = FixedDepositAccountHelper.getInterestRate(interestRateChartData, depositedPeriod);
interestRate -= preClosurePenalInterestRate;
@@ -1608,19 +1589,10 @@ public class FixedDepositTest {
log.info("per day = {}", perDay);
double interestPerDay = interestRateInFraction * perDay;
todaysDate.add(Calendar.MONTH, -1);
todaysDate.add(Calendar.DAY_OF_MONTH, -1);
Integer currentDate = Integer.valueOf(currentDateFormat.format(todaysDate.getTime()));
Integer daysInMonth = todaysDate.getActualMaximum(Calendar.DATE);
daysInMonth = daysInMonth - currentDate + 1;
Float interestPerMonth = (float) (interestPerDay * principal * daysInMonth);
principal += interestPerMonth;
todaysDate.add(Calendar.DATE, daysInMonth);
log.info("{}", monthDayFormat.format(todaysDate.getTime()));
long daysBetween = DAYS.between(activationDate, closingDate);
Float totalInterest = (float) (interestPerDay * principal * daysBetween);
principal += totalInterest;
interestPerMonth = (float) (interestPerDay * principal * currentDate);
log.info("IPM = {}", interestPerMonth);
principal += interestPerMonth;
log.info("principal = {}", principal);
this.fixedDepositAccountHelper.calculatePrematureAmountForFixedDeposit(fixedDepositAccountId, CLOSED_ON_DATE);
@@ -1650,26 +1622,25 @@ public class FixedDepositTest {
this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec);
this.fixedDepositAccountHelper = new FixedDepositAccountHelper(this.requestSpec, this.responseSpec);
DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy", Locale.US);
DateFormat monthDayFormat = new SimpleDateFormat("dd MMM", Locale.US);
DateFormat currentDateFormat = new SimpleDateFormat("dd");
DateTimeFormatter dateFormat = new DateTimeFormatterBuilder().appendPattern("dd MMMM yyyy").toFormatter();
Calendar todaysDate = Calendar.getInstance();
todaysDate.add(Calendar.MONTH, -3);
final String VALID_FROM = dateFormat.format(todaysDate.getTime());
todaysDate.add(Calendar.YEAR, 10);
final String VALID_TO = dateFormat.format(todaysDate.getTime());
LocalDate todaysDate = Utils.getLocalDateOfTenant().minusDays(32);
todaysDate = todaysDate.minusMonths(3);
final String VALID_FROM = dateFormat.format(todaysDate);
todaysDate = todaysDate.plusYears(10);
final String VALID_TO = dateFormat.format(todaysDate);
todaysDate = Calendar.getInstance();
todaysDate.add(Calendar.MONTH, -1);
todaysDate.add(Calendar.DAY_OF_MONTH, -1);
final String SUBMITTED_ON_DATE = dateFormat.format(todaysDate.getTime());
final String APPROVED_ON_DATE = dateFormat.format(todaysDate.getTime());
final String ACTIVATION_DATE = dateFormat.format(todaysDate.getTime());
monthDayFormat.format(todaysDate.getTime());
todaysDate.add(Calendar.MONTH, 1);
todaysDate.add(Calendar.DAY_OF_MONTH, 1);
final String CLOSED_ON_DATE = dateFormat.format(todaysDate.getTime());
todaysDate = Utils.getLocalDateOfTenant().minusDays(32);
todaysDate = todaysDate.minusMonths(1);
todaysDate = todaysDate.minusDays(1);
final String SUBMITTED_ON_DATE = dateFormat.format(todaysDate);
final String APPROVED_ON_DATE = dateFormat.format(todaysDate);
final String ACTIVATION_DATE = dateFormat.format(todaysDate);
LocalDate activationDate = todaysDate;
todaysDate = Utils.getLocalDateOfTenant();
final String CLOSED_ON_DATE = dateFormat.format(todaysDate);
LocalDate closingDate = todaysDate;
Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec);
Assertions.assertNotNull(clientId);
@@ -1705,15 +1676,7 @@ public class FixedDepositTest {
ArrayList<ArrayList<HashMap>> interestRateChartData = FixedDepositProductHelper
.getInterestRateChartSlabsByProductId(this.requestSpec, this.responseSpec, fixedDepositProductId);
Calendar activationDate = Calendar.getInstance();
activationDate.add(Calendar.MONTH, -1);
activationDate.add(Calendar.DAY_OF_MONTH, -1);
ZonedDateTime startDate = ZonedDateTime.ofInstant(activationDate.getTime().toInstant(), this.systemTimeZone.toZoneId());
Calendar prematureClosureDate = Calendar.getInstance();
ZonedDateTime endDate = ZonedDateTime.ofInstant(prematureClosureDate.getTime().toInstant(), this.systemTimeZone.toZoneId());
Integer depositedPeriod = Math.toIntExact(ChronoUnit.MONTHS.between(startDate.toLocalDate(), endDate.toLocalDate()));
Integer depositedPeriod = Math.toIntExact(ChronoUnit.MONTHS.between(activationDate, closingDate));
Float interestRate = FixedDepositAccountHelper.getInterestRate(interestRateChartData, depositedPeriod);
interestRate -= preClosurePenalInterestRate;
@@ -1722,19 +1685,10 @@ public class FixedDepositTest {
log.info("per day = {}", perDay);
double interestPerDay = interestRateInFraction * perDay;
todaysDate.add(Calendar.MONTH, -1);
todaysDate.add(Calendar.DAY_OF_MONTH, -1);
Integer currentDate = Integer.valueOf(currentDateFormat.format(todaysDate.getTime()));
Integer daysInMonth = todaysDate.getActualMaximum(Calendar.DATE);
daysInMonth = daysInMonth - currentDate + 1;
Float interestPerMonth = (float) (interestPerDay * principal * daysInMonth);
principal += interestPerMonth;
todaysDate.add(Calendar.DATE, daysInMonth);
log.info("{}", monthDayFormat.format(todaysDate.getTime()));
long daysBetween = DAYS.between(activationDate, closingDate);
Float totalInterest = (float) (interestPerDay * principal * daysBetween);
principal += totalInterest;
interestPerMonth = (float) (interestPerDay * principal * currentDate);
log.info("IPM = {}", interestPerMonth);
principal += interestPerMonth;
log.info("principal = {}", principal);
this.fixedDepositAccountHelper.calculatePrematureAmountForFixedDeposit(fixedDepositAccountId, CLOSED_ON_DATE);