FINERACT-2104: Accrual Activity Posting for Loans

This commit is contained in:
Soma Sörös
2024-07-09 11:32:31 +02:00
committed by Adam Saghy
parent 67440c47ab
commit 3f4bbf3e14
27 changed files with 620 additions and 30 deletions
@@ -0,0 +1,35 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.event.business.domain.loan.transaction;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
public class LoanTransactionAccrualActivityPostBusinessEvent extends LoanTransactionBusinessEvent {
private static final String TYPE = "LoanTransactionAccrualActivityPostBusinessEvent";
public LoanTransactionAccrualActivityPostBusinessEvent(LoanTransaction value) {
super(value);
}
@Override
public String getType() {
return TYPE;
}
}
@@ -0,0 +1,36 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.event.business.domain.loan.transaction;
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanBusinessEvent;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
public class LoanTransactionAccrualActivityPreBusinessEvent extends LoanBusinessEvent {
private static final String TYPE = "LoanTransactionAccrualActivityPreBusinessEvent";
public LoanTransactionAccrualActivityPreBusinessEvent(Loan value) {
super(value);
}
@Override
public String getType() {
return TYPE;
}
}
@@ -59,6 +59,7 @@ public class LoanTransactionEnumData {
private final boolean downPayment;
private final boolean reAge;
private final boolean reAmortize;
private final boolean accrualActivity;
public LoanTransactionEnumData(final Long id, final String code, final String value) {
this.id = id;
@@ -90,6 +91,7 @@ public class LoanTransactionEnumData {
this.chargeoff = Long.valueOf(27).equals(this.id);
this.downPayment = Long.valueOf(28).equals(this.id);
this.interestPaymentWaiver = Long.valueOf(31).equals(this.id);
this.accrualActivity = Long.valueOf(32).equals(this.id);
this.reAge = Long.valueOf(LoanTransactionType.REAGE.getValue()).equals(this.id);
this.reAmortize = Long.valueOf(LoanTransactionType.REAMORTIZE.getValue()).equals(this.id);
}
@@ -605,6 +605,8 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
this.loanInterestRecalculationDetails.updateLoan(this);
}
this.enableInstallmentLevelDelinquency = enableInstallmentLevelDelinquency;
this.getLoanProductRelatedDetail()
.setEnableAccrualActivityPosting(loanProduct.getLoanProductRelatedDetail().isEnableAccrualActivityPosting());
}
public Integer getNumberOfRepayments() {
@@ -4951,7 +4953,8 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
calendarHistoryDataWrapper, scheduleGeneratorDTO.getNumberOfdays(), scheduleGeneratorDTO.isSkipRepaymentOnFirstDayofMonth(),
holidayDetailDTO, allowCompoundingOnEod, scheduleGeneratorDTO.isFirstRepaymentDateAllowedOnHoliday(),
scheduleGeneratorDTO.isInterestToBeRecoveredFirstWhenGreaterThanEMI(), this.fixedPrincipalPercentagePerInstallment,
scheduleGeneratorDTO.isPrincipalCompoundingDisabledForOverdueLoans(), repaymentStartDateType, getSubmittedOnDate());
scheduleGeneratorDTO.isPrincipalCompoundingDisabledForOverdueLoans(), repaymentStartDateType, getSubmittedOnDate(),
loanProduct.getLoanProductRelatedDetail().isEnableAccrualActivityPosting());
}
public BigDecimal constructLoanTermVariations(FloatingRateDTO floatingRateDTO, BigDecimal annualNominalInterestRate,
@@ -5199,7 +5202,8 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
compoundingCalendarInstance, compoundingFrequencyType, this.loanProduct.preCloseInterestCalculationStrategy(),
rescheduleStrategyMethod, loanCalendar, getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations,
calendarHistoryDataWrapper, numberofdays, isSkipRepaymentonmonthFirst, holidayDetailDTO, allowCompoundingOnEod, false,
false, this.fixedPrincipalPercentagePerInstallment, false, repaymentStartDateType, getSubmittedOnDate());
false, this.fixedPrincipalPercentagePerInstallment, false, repaymentStartDateType, getSubmittedOnDate(),
loanProduct.getLoanProductRelatedDetail().isEnableAccrualActivityPosting());
}
/**
@@ -711,6 +711,10 @@ public class LoanTransaction extends AbstractAuditableWithUTCDateTimeCustom<Long
return getTypeOf().isReAmortize() && isNotReversed();
}
public boolean isAccrualActivity() {
return getTypeOf().isAccrualActivity();
}
public boolean isIdentifiedBy(final Long identifier) {
return getId().equals(identifier);
}
@@ -64,6 +64,7 @@ public enum LoanTransactionType {
REAGE(29, "loanTransactionType.reAge"), //
REAMORTIZE(30, "loanTransactionType.reAmortize"), //
INTEREST_PAYMENT_WAIVER(31, "loanTransactionType.interestPaymentWaiver"), //
ACCRUAL_ACTIVITY(32, "loanTransactionType.accrualActivity"), //
;
private final Integer value;
@@ -111,6 +112,7 @@ public enum LoanTransactionType {
case 29 -> LoanTransactionType.REAGE;
case 30 -> LoanTransactionType.REAMORTIZE;
case 31 -> LoanTransactionType.INTEREST_PAYMENT_WAIVER;
case 32 -> LoanTransactionType.ACCRUAL_ACTIVITY;
default -> LoanTransactionType.INVALID;
};
}
@@ -215,4 +217,8 @@ public enum LoanTransactionType {
public boolean isDownPayment() {
return this.equals(LoanTransactionType.DOWN_PAYMENT);
}
public boolean isAccrualActivity() {
return this.equals(LoanTransactionType.ACCRUAL_ACTIVITY);
}
}
@@ -224,6 +224,7 @@ public final class LoanApplicationTerms {
private Money disbursedPrincipal;
private final LoanScheduleType loanScheduleType;
private final LoanScheduleProcessingType loanScheduleProcessingType;
private final boolean enableAccrualActivityPosting;
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency currency, final Integer loanTermFrequency,
final PeriodFrequencyType loanTermPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery,
@@ -251,7 +252,8 @@ public final class LoanApplicationTerms {
final Boolean enableDownPayment, final BigDecimal disbursedAmountPercentageForDownPayment,
final Boolean isAutoRepaymentForDownPaymentEnabled, final RepaymentStartDateType repaymentStartDateType,
final LocalDate submittedOnDate, final LoanScheduleType loanScheduleType,
final LoanScheduleProcessingType loanScheduleProcessingType, final Integer fixedLength) {
final LoanScheduleProcessingType loanScheduleProcessingType, final Integer fixedLength,
final boolean enableAccrualActivityPosting) {
final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
@@ -270,7 +272,7 @@ public final class LoanApplicationTerms {
isInterestToBeRecoveredFirstWhenGreaterThanEMI, fixedPrincipalPercentagePerInstallment,
isPrincipalCompoundingDisabledForOverdueLoans, enableDownPayment, disbursedAmountPercentageForDownPayment,
isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, submittedOnDate, loanScheduleType, loanScheduleProcessingType,
fixedLength);
fixedLength, enableAccrualActivityPosting);
}
@@ -291,7 +293,8 @@ public final class LoanApplicationTerms {
final boolean isSkipRepaymentOnFirstDayOfMonth, final HolidayDetailDTO holidayDetailDTO, final boolean allowCompoundingOnEod,
final boolean isFirstRepaymentDateAllowedOnHoliday, final boolean isInterestToBeRecoveredFirstWhenGreaterThanEMI,
final BigDecimal fixedPrincipalPercentagePerInstallment, final boolean isPrincipalCompoundingDisabledForOverdueLoans,
final RepaymentStartDateType repaymentStartDateType, final LocalDate submittedOnDate) {
final RepaymentStartDateType repaymentStartDateType, final LocalDate submittedOnDate,
final boolean enableAccrualActivityPosting) {
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
@@ -343,7 +346,7 @@ public final class LoanApplicationTerms {
isInterestToBeRecoveredFirstWhenGreaterThanEMI, fixedPrincipalPercentagePerInstallment,
isPrincipalCompoundingDisabledForOverdueLoans, isDownPaymentEnabled, disbursedAmountPercentageForDownPayment,
isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, submittedOnDate, loanScheduleType, loanScheduleProcessingType,
fixedLength);
fixedLength, enableAccrualActivityPosting);
}
private LoanApplicationTerms(final ApplicationCurrency currency, final Integer loanTermFrequency,
@@ -372,7 +375,7 @@ public final class LoanApplicationTerms {
final boolean isPrincipalCompoundingDisabledForOverdueLoans, final boolean isDownPaymentEnabled,
final BigDecimal disbursedAmountPercentageForDownPayment, final boolean isAutoRepaymentForDownPaymentEnabled,
final RepaymentStartDateType repaymentStartDateType, final LocalDate submittedOnDate, final LoanScheduleType loanScheduleType,
final LoanScheduleProcessingType loanScheduleProcessingType, final Integer fixedLength) {
final LoanScheduleProcessingType loanScheduleProcessingType, final Integer fixedLength, boolean enableAccrualActivityPosting) {
this.currency = currency;
this.loanTermFrequency = loanTermFrequency;
@@ -426,6 +429,7 @@ public final class LoanApplicationTerms {
this.numberOfDays = numberOfDays;
this.loanCalendar = loanCalendar;
this.enableAccrualActivityPosting = enableAccrualActivityPosting;
this.approvedPrincipal = Money.of(principal.getCurrency(), approvedAmount);
this.variationsDataWrapper = new LoanTermVariationsDataWrapper(loanTermVariations);
this.actualNumberOfRepayments = numberOfRepayments + getLoanTermVariations().adjustNumberOfRepayments();
@@ -1333,7 +1337,7 @@ public final class LoanApplicationTerms {
this.graceOnArrearsAgeing, this.daysInMonthType.getValue(), this.daysInYearType.getValue(),
this.interestRecalculationEnabled, this.isEqualAmortization, this.isDownPaymentEnabled,
this.disbursedAmountPercentageForDownPayment, this.isAutoRepaymentForDownPaymentEnabled, this.loanScheduleType,
this.loanScheduleProcessingType, this.fixedLength);
this.loanScheduleProcessingType, this.fixedLength, this.enableAccrualActivityPosting);
}
public Integer getLoanTermFrequency() {
@@ -30,6 +30,7 @@ import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
import org.apache.fineract.portfolio.collectionsheet.command.CollectionSheetBulkDisbursalCommand;
import org.apache.fineract.portfolio.collectionsheet.command.CollectionSheetBulkRepaymentCommand;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
import org.springframework.transaction.annotation.Transactional;
@@ -52,6 +53,9 @@ public interface LoanWritePlatformService {
CommandProcessingResult makeLoanRepaymentWithChargeRefundChargeType(LoanTransactionType repaymentTransactionType, Long loanId,
JsonCommand command, boolean isRecoveryRepayment, String chargeRefundChargeType);
@Transactional
Loan makeAccrualActivityTransaction(Loan loan, LoanRepaymentScheduleInstallment installment, LocalDate currentDate);
@Transactional
CommandProcessingResult makeInterestPaymentWaiver(JsonCommand command);
@@ -163,4 +163,7 @@ public interface LoanProductConstants {
String ADVANCED_PAYMENT_ALLOCATION_STRATEGY = "advanced-payment-allocation-strategy";
String FIXED_LENGTH = "fixedLength";
String ENABLE_ACCRUAL_ACTIVITY_POSTING = "enableAccrualActivityPosting";
}
@@ -169,6 +169,8 @@ final class LoanProductsApiResourceSwagger {
public Boolean enableAutoRepaymentForDownPayment;
@Schema(example = "1")
public Integer repaymentStartDateType;
@Schema(example = "false")
public Boolean enableAccrualActivityPosting;
// Interest Recalculation
@Schema(example = "false")
@@ -1277,6 +1279,8 @@ final class LoanProductsApiResourceSwagger {
public EnumOptionData loanScheduleType;
@Schema(example = "HORIZONTAL")
public EnumOptionData loanScheduleProcessingType;
@Schema(example = "false")
public Boolean enableAccrualActivityPosting;
}
@Schema(description = "PutLoanProductsProductIdRequest")
@@ -1487,6 +1491,8 @@ final class LoanProductsApiResourceSwagger {
public List<GetLoanProductsProductIdResponse.GetLoanPaymentChannelToFundSourceMappings> paymentChannelToFundSourceMappings;
public List<GetLoanProductsProductIdResponse.GetLoanFeeToIncomeAccountMappings> feeToIncomeAccountMappings;
public List<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings;
@Schema(example = "false")
public Boolean enableAccrualActivityPosting;
// Multi Disburse
@Schema(example = "true")
@@ -148,6 +148,7 @@ public class LoanProductData implements Serializable {
private Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings;
private Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings;
private Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings;
private final boolean enableAccrualActivityPosting;
// rates
private final boolean isRatesEnabled;
@@ -323,6 +324,7 @@ public class LoanProductData implements Serializable {
final EnumOptionData loanScheduleProcessingType = null;
final EnumOptionData loanScheduleTypeOptions = null;
final EnumOptionData loanScheduleProcessingTypeOptions = null;
final boolean enableAccrualActivityPosting = false;
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
@@ -343,7 +345,7 @@ public class LoanProductData implements Serializable {
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
paymentAllocation, creditAllocation, repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType,
loanScheduleProcessingType, fixedLength);
loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting);
}
@@ -443,6 +445,7 @@ public class LoanProductData implements Serializable {
final boolean enableInstallmentLevelDelinquency = false;
final EnumOptionData loanScheduleType = null;
final EnumOptionData loanScheduleProcessingType = null;
final boolean enableAccrualActivityPosting = false;
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
@@ -463,7 +466,7 @@ public class LoanProductData implements Serializable {
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
paymentAllocation, creditAllocation, repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType,
loanScheduleProcessingType, fixedLength);
loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting);
}
@@ -570,6 +573,7 @@ public class LoanProductData implements Serializable {
final boolean enableInstallmentLevelDelinquency = false;
final EnumOptionData loanScheduleType = LoanScheduleType.CUMULATIVE.asEnumOptionData();
final EnumOptionData loanScheduleProcessingType = LoanScheduleProcessingType.HORIZONTAL.asEnumOptionData();
final boolean enableAccrualActivityPosting = false;
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
@@ -590,7 +594,7 @@ public class LoanProductData implements Serializable {
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
paymentAllocation, creditAllocation, repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType,
loanScheduleProcessingType, fixedLength);
loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting);
}
@@ -691,6 +695,7 @@ public class LoanProductData implements Serializable {
final boolean enableInstallmentLevelDelinquency = false;
final EnumOptionData loanScheduleType = null;
final EnumOptionData loanScheduleProcessingType = null;
final boolean enableAccrualActivityPosting = false;
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
@@ -711,7 +716,7 @@ public class LoanProductData implements Serializable {
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
paymentAllocation, creditAllocationData, repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType,
loanScheduleProcessingType, fixedLength);
loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting);
}
public static LoanProductData withAccountingDetails(final LoanProductData productData, final Map<String, Object> accountingMappings,
@@ -761,7 +766,8 @@ public class LoanProductData implements Serializable {
final BigDecimal disbursedAmountPercentageForDownPayment, final boolean enableAutoRepaymentForDownPayment,
final Collection<AdvancedPaymentData> paymentAllocation, final Collection<CreditAllocationData> creditAllocation,
final EnumOptionData repaymentStartDateType, final boolean enableInstallmentLevelDelinquency,
final EnumOptionData loanScheduleType, final EnumOptionData loanScheduleProcessingType, final Integer fixedLength) {
final EnumOptionData loanScheduleType, final EnumOptionData loanScheduleProcessingType, final Integer fixedLength,
final boolean enableAccrualActivityPosting) {
this.id = id;
this.name = name;
this.shortName = shortName;
@@ -897,6 +903,7 @@ public class LoanProductData implements Serializable {
this.loanScheduleProcessingType = loanScheduleProcessingType;
this.loanScheduleTypeOptions = null;
this.loanScheduleProcessingTypeOptions = null;
this.enableAccrualActivityPosting = enableAccrualActivityPosting;
}
public LoanProductData(final LoanProductData productData, final Collection<ChargeData> chargeOptions,
@@ -1072,6 +1079,7 @@ public class LoanProductData implements Serializable {
this.loanScheduleProcessingType = productData.getLoanScheduleProcessingType();
this.loanScheduleProcessingTypeOptions = loanScheduleProcessingTypeOptions;
this.loanScheduleTypeOptions = loanScheduleTypeOptions;
this.enableAccrualActivityPosting = productData.enableAccrualActivityPosting;
}
private Collection<ChargeData> nullIfEmpty(final Collection<ChargeData> charges) {
@@ -439,6 +439,9 @@ public class LoanProduct extends AbstractPersistableCustom<Long> {
final Integer fixedLength = command.integerValueOfParameterNamed(LoanProductConstants.FIXED_LENGTH);
final boolean enableAccrualActivityPosting = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ENABLE_ACCRUAL_ACTIVITY_POSTING);
return new LoanProduct(fund, loanTransactionProcessingStrategy, loanProductPaymentAllocationRules, loanProductCreditAllocationRules,
name, shortName, description, currency, principal, minPrincipal, maxPrincipal, interestRatePerPeriod,
minInterestRatePerPeriod, maxInterestRatePerPeriod, interestFrequencyType, annualInterestRate, interestMethod,
@@ -457,7 +460,8 @@ public class LoanProduct extends AbstractPersistableCustom<Long> {
isEqualAmortization, productRates, fixedPrincipalPercentagePerInstallment, disallowExpectedDisbursements,
allowApprovedDisbursedAmountsOverApplied, overAppliedCalculationType, overAppliedNumber, dueDaysForRepaymentEvent,
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType, loanScheduleProcessingType, fixedLength);
repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType, loanScheduleProcessingType, fixedLength,
enableAccrualActivityPosting);
}
@@ -674,7 +678,8 @@ public class LoanProduct extends AbstractPersistableCustom<Long> {
final boolean enableDownPayment, final BigDecimal disbursedAmountPercentageForDownPayment,
final boolean enableAutoRepaymentForDownPayment, final RepaymentStartDateType repaymentStartDateType,
final boolean enableInstallmentLevelDelinquency, final LoanScheduleType loanScheduleType,
final LoanScheduleProcessingType loanScheduleProcessingType, final Integer fixedLength) {
final LoanScheduleProcessingType loanScheduleProcessingType, final Integer fixedLength,
final boolean enableAccrualActivityPosting) {
this.fund = fund;
this.transactionProcessingStrategyCode = transactionProcessingStrategyCode;
@@ -723,7 +728,7 @@ public class LoanProduct extends AbstractPersistableCustom<Long> {
recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment, graceOnInterestCharged, amortizationMethod,
inArrearsTolerance, graceOnArrearsAgeing, daysInMonthType.getValue(), daysInYearType.getValue(),
isInterestRecalculationEnabled, isEqualAmortization, enableDownPayment, disbursedAmountPercentageForDownPayment,
enableAutoRepaymentForDownPayment, loanScheduleType, loanScheduleProcessingType, fixedLength);
enableAutoRepaymentForDownPayment, loanScheduleType, loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting);
this.loanProductMinMaxConstraints = new LoanProductMinMaxConstraints(defaultMinPrincipal, defaultMaxPrincipal,
defaultMinNominalInterestRatePerPeriod, defaultMaxNominalInterestRatePerPeriod, defaultMinNumberOfInstallments,
@@ -908,6 +913,13 @@ public class LoanProduct extends AbstractPersistableCustom<Long> {
this.isLinkedToFloatingInterestRate = newValue;
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.ENABLE_ACCRUAL_ACTIVITY_POSTING,
this.getLoanProductRelatedDetail().isEnableAccrualActivityPosting())) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ENABLE_ACCRUAL_ACTIVITY_POSTING);
actualChanges.put(LoanProductConstants.ENABLE_ACCRUAL_ACTIVITY_POSTING, newValue);
this.getLoanProductRelatedDetail().setEnableAccrualActivityPosting(newValue);
}
if (this.isLinkedToFloatingInterestRate) {
actualChanges.putAll(loanProductFloatingRates().update(command, floatingRate));
this.loanProductRelatedDetail.updateForFloatingInterestRates();
@@ -150,6 +150,9 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
@Enumerated(EnumType.STRING)
private LoanScheduleProcessingType loanScheduleProcessingType;
@Column(name = "enable_accrual_activity_posting", nullable = false)
private boolean enableAccrualActivityPosting = false;
public static LoanProductRelatedDetail createFrom(final MonetaryCurrency currency, final BigDecimal principal,
final BigDecimal nominalInterestRatePerPeriod, final PeriodFrequencyType interestRatePeriodFrequencyType,
final BigDecimal nominalAnnualInterestRate, final InterestMethod interestMethod,
@@ -161,7 +164,8 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
final Integer daysInYearType, final boolean isInterestRecalculationEnabled, final boolean isEqualAmortization,
final boolean enableDownPayment, final BigDecimal disbursedAmountPercentageForDownPayment,
final boolean enableAutoRepaymentForDownPayment, final LoanScheduleType loanScheduleType,
final LoanScheduleProcessingType loanScheduleProcessingType, final Integer fixedLength) {
final LoanScheduleProcessingType loanScheduleProcessingType, final Integer fixedLength,
final boolean enableAccrualActivityPosting) {
return new LoanProductRelatedDetail(currency, principal, nominalInterestRatePerPeriod, interestRatePeriodFrequencyType,
nominalAnnualInterestRate, interestMethod, interestCalculationPeriodMethod, allowPartialPeriodInterestCalcualtion,
@@ -169,7 +173,7 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment, graceOnInterestCharged, amortizationMethod,
inArrearsTolerance, graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
isEqualAmortization, enableDownPayment, disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment,
loanScheduleType, loanScheduleProcessingType, fixedLength);
loanScheduleType, loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting);
}
protected LoanProductRelatedDetail() {
@@ -187,7 +191,8 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
final Integer daysInYearType, final boolean isInterestRecalculationEnabled, final boolean isEqualAmortization,
final boolean enableDownPayment, final BigDecimal disbursedAmountPercentageForDownPayment,
final boolean enableAutoRepaymentForDownPayment, final LoanScheduleType loanScheduleType,
final LoanScheduleProcessingType loanScheduleProcessingType, final Integer fixedLength) {
final LoanScheduleProcessingType loanScheduleProcessingType, final Integer fixedLength,
final boolean enableAccrualActivityPosting) {
this.currency = currency;
this.principal = defaultPrincipal;
this.nominalInterestRatePerPeriod = defaultNominalInterestRatePerPeriod;
@@ -220,6 +225,7 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
this.enableAutoRepaymentForDownPayment = enableAutoRepaymentForDownPayment;
this.loanScheduleType = loanScheduleType;
this.loanScheduleProcessingType = loanScheduleProcessingType;
this.enableAccrualActivityPosting = enableAccrualActivityPosting;
}
private Integer defaultToNullIfZero(final Integer value) {
@@ -319,6 +319,8 @@ public final class LoanEnumerations {
"Re-age");
case REAMORTIZE -> new LoanTransactionEnumData(LoanTransactionType.REAMORTIZE.getValue().longValue(),
LoanTransactionType.REAMORTIZE.getCode(), "Re-amortize");
case ACCRUAL_ACTIVITY -> new LoanTransactionEnumData(LoanTransactionType.ACCRUAL_ACTIVITY.getValue().longValue(),
LoanTransactionType.ACCRUAL_ACTIVITY.getCode(), "Accrual Activity");
};
}