Skip to content

Commit

Permalink
FINERACT-1981: Introduce Interest should not be calculated on past du…
Browse files Browse the repository at this point in the history
…e principal amount
  • Loading branch information
janez89 authored and adamsaghy committed Nov 29, 2024
1 parent 3858611 commit 4cb849f
Show file tree
Hide file tree
Showing 17 changed files with 287 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,14 @@
"null",
"boolean"
]
},
{
"default": null,
"name": "disallowInterestCalculationOnPastDue",
"type": [
"null",
"boolean"
]
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,14 @@
"null",
"boolean"
]
},
{
"default": null,
"name": "disallowInterestCalculationOnPastDue",
"type": [
"null",
"boolean"
]
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public class LoanInterestRecalculationData {
private Boolean isCompoundingToBePostedAsTransaction;
private CalendarData compoundingCalendarData;
private Boolean allowCompoundingOnEod;
private Boolean disallowInterestCalculationOnPastDue;

public LoanInterestRecalculationData(final Long id, final Long loanId, final EnumOptionData interestRecalculationCompoundingType,
final EnumOptionData rescheduleStrategyType, final CalendarData calendarData,
Expand All @@ -56,7 +57,7 @@ public LoanInterestRecalculationData(final Long id, final Long loanId, final Enu
final EnumOptionData recalculationCompoundingFrequencyType, final Integer recalculationCompoundingFrequencyInterval,
final EnumOptionData recalculationCompoundingFrequencyNthDay, final EnumOptionData recalculationCompoundingFrequencyWeekday,
final Integer recalculationCompoundingFrequencyOnDay, final Boolean isCompoundingToBePostedAsTransaction,
final Boolean allowCompoundingOnEod) {
final Boolean allowCompoundingOnEod, final Boolean disallowInterestCalculationOnPastDue) {
this.id = id;
this.loanId = loanId;
this.interestRecalculationCompoundingType = interestRecalculationCompoundingType;
Expand All @@ -75,6 +76,7 @@ public LoanInterestRecalculationData(final Long id, final Long loanId, final Enu
this.compoundingCalendarData = compoundingCalendarData;
this.isCompoundingToBePostedAsTransaction = isCompoundingToBePostedAsTransaction;
this.allowCompoundingOnEod = allowCompoundingOnEod;
this.disallowInterestCalculationOnPastDue = disallowInterestCalculationOnPastDue;
}

public LoanInterestRecalculationData withCalendarData(final CalendarData calendarData, CalendarData compoundingCalendarData) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ public class LoanInterestRecalculationDetails extends AbstractPersistableCustom<
@Column(name = "allow_compounding_on_eod")
private Boolean allowCompoundingOnEod;

@Column(name = "disallow_interest_calc_on_past_due")
private Boolean disallowInterestCalculationOnPastDue;

protected LoanInterestRecalculationDetails() {
// Default constructor for jpa repository
}
Expand All @@ -96,7 +99,7 @@ private LoanInterestRecalculationDetails(final Integer interestRecalculationComp
final Integer restFrequencyType, final Integer restInterval, final Integer restFrequencyNthDay, Integer restFrequencyWeekday,
Integer restFrequencyOnDay, Integer compoundingFrequencyType, Integer compoundingInterval, Integer compoundingFrequencyNthDay,
Integer compoundingFrequencyWeekday, Integer compoundingFrequencyOnDay, final boolean isCompoundingToBePostedAsTransaction,
final boolean allowCompoundingOnEod) {
final boolean allowCompoundingOnEod, final boolean disallowInterestCalculationOnPastDue) {
this.interestRecalculationCompoundingMethod = interestRecalculationCompoundingMethod;
this.rescheduleStrategyMethod = rescheduleStrategyMethod;
this.restFrequencyNthDay = restFrequencyNthDay;
Expand All @@ -111,6 +114,7 @@ private LoanInterestRecalculationDetails(final Integer interestRecalculationComp
this.compoundingInterval = compoundingInterval;
this.isCompoundingToBePostedAsTransaction = isCompoundingToBePostedAsTransaction;
this.allowCompoundingOnEod = allowCompoundingOnEod;
this.disallowInterestCalculationOnPastDue = disallowInterestCalculationOnPastDue;
}

public static LoanInterestRecalculationDetails createFrom(
Expand All @@ -127,7 +131,8 @@ public static LoanInterestRecalculationDetails createFrom(
loanProductInterestRecalculationDetails.getCompoundingFrequencyWeekday(),
loanProductInterestRecalculationDetails.getCompoundingFrequencyOnDay(),
loanProductInterestRecalculationDetails.getIsCompoundingToBePostedAsTransaction(),
loanProductInterestRecalculationDetails.allowCompoundingOnEod());
loanProductInterestRecalculationDetails.allowCompoundingOnEod(),
loanProductInterestRecalculationDetails.disallowInterestCalculationOnPastDue());
}

public void updateLoan(final Loan loan) {
Expand Down Expand Up @@ -189,4 +194,8 @@ public boolean isCompoundingToBePostedAsTransaction() {
public boolean allowCompoundingOnEod() {
return this.allowCompoundingOnEod;
}

public Boolean disallowInterestCalculationOnPastDue() {
return disallowInterestCalculationOnPastDue;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ public interface LoanProductConstants {
String recalculationCompoundingFrequencyNthDayParamName = "recalculationCompoundingFrequencyNthDayType";
String recalculationCompoundingFrequencyOnDayParamName = "recalculationCompoundingFrequencyOnDayType";
String isCompoundingToBePostedAsTransactionParamName = "isCompoundingToBePostedAsTransaction";
String disallowInterestCalculationOnPastDueParamName = "disallowInterestCalculationOnPastDue";

// Guarantee related
String holdGuaranteeFundsParamName = "holdGuaranteeFunds";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,8 @@ private PostLoanProductsRequest() {}
public Boolean isCompoundingToBePostedAsTransaction;
@Schema(example = "false")
public Boolean allowCompoundingOnEod;
@Schema(example = "false")
public Boolean disallowInterestCalculationOnPastDue;

// Accounting
@Schema(example = "3")
Expand Down Expand Up @@ -520,6 +522,8 @@ private GetLoanProductsPreClosureInterestCalculationStrategy() {}
public GetLoanProductsPreClosureInterestCalculationStrategy preClosureInterestCalculationStrategy;
@Schema(example = "true")
public Boolean isArrearsBasedOnOriginalSchedule;
@Schema(example = "false")
public Boolean disallowInterestCalculationOnPastDue;
@Schema(example = "true")
public Boolean isCompoundingToBePostedAsTransaction;
@Schema(example = "true")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1182,7 +1182,7 @@ calendarData, getRecalculationRestFrequencyType(), getRecalculationRestFrequency
getInterestRecalculationRestOnDayType(), compoundingCalendarData, getRecalculationCompoundingFrequencyType(),
getRecalculationCompoundingFrequencyInterval(), getInterestRecalculationCompoundingNthDayType(),
getInterestRecalculationCompoundingWeekDayType(), getInterestRecalculationCompoundingOnDayType(),
isCompoundingToBePostedAsTransaction(), allowCompoundingOnEod());
isCompoundingToBePostedAsTransaction(), allowCompoundingOnEod(), disallowInterestCalculationOnPastDue());
}

private EnumOptionData getRescheduleStrategyType() {
Expand Down Expand Up @@ -1279,6 +1279,11 @@ public Boolean allowCompoundingOnEod() {
return isInterestRecalculationEnabled() ? this.interestRecalculationData.isAllowCompoundingOnEod() : null;
}

@SuppressFBWarnings("NP_BOOLEAN_RETURN_NULL")
public Boolean disallowInterestCalculationOnPastDue() {
return isInterestRecalculationEnabled() ? this.interestRecalculationData.disallowInterestCalculationOnPastDue() : null;
}

public void setLoanProductConfigurableAttributes(LoanProductConfigurableAttributes loanProductConfigurableAttributes) {
this.allowAttributeOverrides = loanProductConfigurableAttributes;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public class LoanProductInterestRecalculationData implements Serializable {
private final boolean isCompoundingToBePostedAsTransaction;
private final EnumOptionData preClosureInterestCalculationStrategy;
private final boolean allowCompoundingOnEod;
private final Boolean disallowInterestCalculationOnPastDue;

public LoanProductInterestRecalculationData(final Long id, final Long productId,
final EnumOptionData interestRecalculationCompoundingType, final EnumOptionData rescheduleStrategyType,
Expand All @@ -59,7 +60,8 @@ public LoanProductInterestRecalculationData(final Long id, final Long productId,
final Integer recalculationCompoundingFrequencyInterval, final EnumOptionData recalculationCompoundingFrequencyNthDay,
final EnumOptionData recalculationCompoundingFrequencyWeekday, final Integer recalculationCompoundingFrequencyOnDay,
final boolean isArrearsBasedOnOriginalSchedule, boolean isCompoundingToBePostedAsTransaction,
final EnumOptionData preCloseInterestCalculationStrategy, final boolean allowCompoundingOnEod) {
final EnumOptionData preCloseInterestCalculationStrategy, final boolean allowCompoundingOnEod,
final Boolean disallowInterestCalculationOnPastDue) {
this.id = id;
this.productId = productId;
this.interestRecalculationCompoundingType = interestRecalculationCompoundingType;
Expand All @@ -78,6 +80,7 @@ public LoanProductInterestRecalculationData(final Long id, final Long productId,
this.preClosureInterestCalculationStrategy = preCloseInterestCalculationStrategy;
this.isCompoundingToBePostedAsTransaction = isCompoundingToBePostedAsTransaction;
this.allowCompoundingOnEod = allowCompoundingOnEod;
this.disallowInterestCalculationOnPastDue = disallowInterestCalculationOnPastDue;
}

public static LoanProductInterestRecalculationData sensibleDefaultsForNewLoanProductCreation() {
Expand All @@ -101,12 +104,15 @@ public static LoanProductInterestRecalculationData sensibleDefaultsForNewLoanPro
final EnumOptionData preCloseInterestCalculationStrategy = preCloseInterestCalculationStrategy(
LoanPreClosureInterestCalculationStrategy.TILL_PRE_CLOSURE_DATE);
final boolean allowCompoundingOnEod = false;
final boolean disallowInterestCalculationOnPastDue = false;

return new LoanProductInterestRecalculationData(id, productId, interestRecalculationCompoundingType, rescheduleStrategyType,
recalculationRestFrequencyType, recalculationRestFrequencyInterval, recalculationRestFrequencyNthDay,
recalculationRestFrequencyWeekday, recalculationRestFrequencyOnDay, recalculationCompoundingFrequencyType,
recalculationCompoundingFrequencyInterval, recalculationCompoundingFrequencyNthDay,
recalculationCompoundingFrequencyWeekday, recalculationCompoundingFrequencyOnDay, isArrearsBasedOnOriginalSchedule,
isCompoundingToBePostedAsTransaction, preCloseInterestCalculationStrategy, allowCompoundingOnEod);
isCompoundingToBePostedAsTransaction, preCloseInterestCalculationStrategy, allowCompoundingOnEod,
disallowInterestCalculationOnPastDue);
}

public boolean isArrearsBasedOnOriginalSchedule() {
Expand All @@ -124,4 +130,8 @@ public boolean isIsArrearsBasedOnOriginalSchedule() {
public boolean isIsCompoundingToBePostedAsTransaction() {
return isCompoundingToBePostedAsTransaction;
}

public Boolean disallowInterestCalculationOnPastDue() {
return disallowInterestCalculationOnPastDue;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
@Column(name = "allow_compounding_on_eod")
private Boolean allowCompoundingOnEod;

@Column(name = "disallow_interest_calc_on_past_due")
private Boolean disallowInterestCalculationOnPastDue;

protected LoanProductInterestRecalculationDetails() {
//
}
Expand Down Expand Up @@ -162,11 +165,14 @@ public static LoanProductInterestRecalculationDetails createFrom(final JsonComma
final boolean isCompoundingToBePostedAsTransaction = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.isCompoundingToBePostedAsTransactionParamName);

final boolean disallowInterestCalculationOnPastDue = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.disallowInterestCalculationOnPastDueParamName);

return new LoanProductInterestRecalculationDetails(interestRecalculationCompoundingMethod, loanRescheduleStrategyMethod,
recurrenceFrequency, recurrenceInterval, recurrenceOnNthDay, recurrenceOnDay, recurrenceOnWeekday,
compoundingRecurrenceFrequency, compoundingInterval, compoundingRecurrenceOnNthDay, compoundingRecurrenceOnDay,
compoundingRecurrenceOnWeekday, isArrearsBasedOnOriginalSchedule, preCloseInterestCalculationStrategy,
isCompoundingToBePostedAsTransaction, allowCompoundingOnEod);
isCompoundingToBePostedAsTransaction, allowCompoundingOnEod, disallowInterestCalculationOnPastDue);
}

private LoanProductInterestRecalculationDetails(final Integer interestRecalculationCompoundingMethod,
Expand All @@ -175,7 +181,8 @@ private LoanProductInterestRecalculationDetails(final Integer interestRecalculat
Integer compoundingFrequencyType, Integer compoundingInterval, final Integer compoundingFrequencyNthDay,
final Integer compoundingFrequencyOnDay, final Integer compoundingFrequencyWeekday,
final boolean isArrearsBasedOnOriginalSchedule, final Integer preCloseInterestCalculationStrategy,
final boolean isCompoundingToBePostedAsTransaction, final boolean allowCompoundingOnEod) {
final boolean isCompoundingToBePostedAsTransaction, final boolean allowCompoundingOnEod,
final boolean disallowInterestCalculationOnPastDue) {
this.interestRecalculationCompoundingMethod = interestRecalculationCompoundingMethod;
this.rescheduleStrategyMethod = rescheduleStrategyMethod;
this.restFrequencyType = restFrequencyType;
Expand All @@ -192,6 +199,7 @@ private LoanProductInterestRecalculationDetails(final Integer interestRecalculat
this.preClosureInterestCalculationStrategy = preCloseInterestCalculationStrategy;
this.isCompoundingToBePostedAsTransaction = isCompoundingToBePostedAsTransaction;
this.allowCompoundingOnEod = allowCompoundingOnEod;
this.disallowInterestCalculationOnPastDue = disallowInterestCalculationOnPastDue;
}

public void updateProduct(final LoanProduct loanProduct) {
Expand Down Expand Up @@ -406,6 +414,13 @@ public void update(final JsonCommand command, final Map<String, Object> actualCh
this.isCompoundingToBePostedAsTransaction = newValue;
}

if (command.isChangeInBooleanParameterNamed(LoanProductConstants.disallowInterestCalculationOnPastDueParamName,
this.disallowInterestCalculationOnPastDue)) {
final boolean newValue = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.disallowInterestCalculationOnPastDueParamName);
actualChanges.put(LoanProductConstants.disallowInterestCalculationOnPastDueParamName, newValue);
this.disallowInterestCalculationOnPastDue = newValue;
}
}

public RecalculationFrequencyType getRestFrequencyType() {
Expand Down Expand Up @@ -463,4 +478,8 @@ public Boolean getIsCompoundingToBePostedAsTransaction() {
public Boolean allowCompoundingOnEod() {
return this.allowCompoundingOnEod;
}

public Boolean disallowInterestCalculationOnPastDue() {
return disallowInterestCalculationOnPastDue;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -982,6 +982,10 @@ private void recalculateInterestForDate(LocalDate currentDate, ProgressiveTransa

private void adjustOverduePrincipalForInstallment(LocalDate currentDate, LoanRepaymentScheduleInstallment currentInstallment,
Money overduePrincipal, Money aggregatedOverDuePrincipal, ProgressiveTransactionCtx ctx) {
if (currentInstallment.getLoan().getLoanInterestRecalculationDetails().disallowInterestCalculationOnPastDue()) {
return;
}

LocalDate fromDate = currentInstallment.getFromDate();
LocalDate toDate = currentInstallment.getDueDate();
boolean hasUpdate = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,11 @@ public class LoanInterestRecalculationCOBBusinessStep implements LoanCOBBusiness
@Override
public Loan execute(Loan loan) {
if (!loan.isInterestBearing() || !loan.getStatus().isActive() || loan.isNpa() || loan.isChargedOff()
|| !loan.isInterestRecalculationEnabledForProduct()) {
log.debug("Skip processing loan interest recalculation [{}] - reason: not interest bearing loan or not active.", loan.getId());
|| !loan.isInterestRecalculationEnabledForProduct()
|| loan.getLoanInterestRecalculationDetails().disallowInterestCalculationOnPastDue()) {
log.debug(
"Skip processing loan interest recalculation [{}] - Possible reasons: Loan is not an interest bearing loan, Loan is not active, Interest recalculation on past due is disabled on this loan",
loan.getId());
return loan;
}

Expand Down
Loading

0 comments on commit 4cb849f

Please sign in to comment.