Skip to content

Commit

Permalink
FINERACT-2148: loan charge off behaviour configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
magyari-adam committed Nov 27, 2024
1 parent 2e89c40 commit 390238e
Show file tree
Hide file tree
Showing 17 changed files with 237 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* 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.portfolio.loanaccount.domain;

import java.util.Arrays;
import java.util.List;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.data.StringEnumOptionData;

@Getter
@RequiredArgsConstructor
public enum LoanChargeOffBehaviour {

REGULAR("chargeOffBehaviour.regular", "Regular"), //
ZERO_INTEREST("chargeOffBehaviour.zeroInterest", "Zero interest after charge-off"), //
;

private final String code;
private final String humanReadableName;

public static List<StringEnumOptionData> getValuesAsStringEnumOptionDataList() {
return Arrays.stream(values()).map(v -> new StringEnumOptionData(v.name(), v.getCode(), v.getHumanReadableName())).toList();
}

public StringEnumOptionData getValueAsStringEnumOptionData() {
return new StringEnumOptionData(name(), getCode(), getHumanReadableName());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsDataWrapper;
import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeOffBehaviour;
import org.apache.fineract.portfolio.loanproduct.domain.AmortizationMethod;
import org.apache.fineract.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
Expand Down Expand Up @@ -228,6 +229,7 @@ public final class LoanApplicationTerms {
private LoanScheduleProcessingType loanScheduleProcessingType;
private boolean enableAccrualActivityPosting;
private List<LoanSupportedInterestRefundTypes> supportedInterestRefundTypes;
private LoanChargeOffBehaviour chargeOffBehaviour;

private LoanApplicationTerms(Builder builder) {
this.currency = builder.currency;
Expand Down Expand Up @@ -458,7 +460,8 @@ public static LoanApplicationTerms assembleFrom(final ApplicationCurrency curren
final Boolean isAutoRepaymentForDownPaymentEnabled, final RepaymentStartDateType repaymentStartDateType,
final LocalDate submittedOnDate, final LoanScheduleType loanScheduleType,
final LoanScheduleProcessingType loanScheduleProcessingType, final Integer fixedLength,
final boolean enableAccrualActivityPosting, final List<LoanSupportedInterestRefundTypes> supportedInterestRefundTypes) {
final boolean enableAccrualActivityPosting, final List<LoanSupportedInterestRefundTypes> supportedInterestRefundTypes,
final LoanChargeOffBehaviour chargeOffBehaviour) {

final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
Expand All @@ -477,7 +480,7 @@ public static LoanApplicationTerms assembleFrom(final ApplicationCurrency curren
isInterestToBeRecoveredFirstWhenGreaterThanEMI, fixedPrincipalPercentagePerInstallment,
isPrincipalCompoundingDisabledForOverdueLoans, enableDownPayment, disbursedAmountPercentageForDownPayment,
isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, submittedOnDate, loanScheduleType, loanScheduleProcessingType,
fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes);
fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour);

}

Expand Down Expand Up @@ -551,7 +554,7 @@ public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applic
isPrincipalCompoundingDisabledForOverdueLoans, isDownPaymentEnabled, disbursedAmountPercentageForDownPayment,
isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, submittedOnDate, loanScheduleType, loanScheduleProcessingType,
fixedLength, loanProductRelatedDetail.isEnableAccrualActivityPosting(),
loanProductRelatedDetail.getSupportedInterestRefundTypes());
loanProductRelatedDetail.getSupportedInterestRefundTypes(), loanProductRelatedDetail.getChargeOffBehaviour());
}

private LoanApplicationTerms(final ApplicationCurrency currency, final Integer loanTermFrequency,
Expand Down Expand Up @@ -581,7 +584,7 @@ private LoanApplicationTerms(final ApplicationCurrency currency, final Integer l
final BigDecimal disbursedAmountPercentageForDownPayment, final boolean isAutoRepaymentForDownPaymentEnabled,
final RepaymentStartDateType repaymentStartDateType, final LocalDate submittedOnDate, final LoanScheduleType loanScheduleType,
final LoanScheduleProcessingType loanScheduleProcessingType, final Integer fixedLength, boolean enableAccrualActivityPosting,
final List<LoanSupportedInterestRefundTypes> supportedInterestRefundTypes) {
final List<LoanSupportedInterestRefundTypes> supportedInterestRefundTypes, final LoanChargeOffBehaviour chargeOffBehaviour) {

this.currency = currency;
this.loanTermFrequency = loanTermFrequency;
Expand Down Expand Up @@ -680,6 +683,7 @@ private LoanApplicationTerms(final ApplicationCurrency currency, final Integer l
this.loanScheduleProcessingType = loanScheduleProcessingType;
this.fixedLength = fixedLength;
this.supportedInterestRefundTypes = supportedInterestRefundTypes;
this.chargeOffBehaviour = chargeOffBehaviour;
}

public Money adjustPrincipalIfLastRepaymentPeriod(final Money principalForPeriod, final Money totalCumulativePrincipalToDate,
Expand Down Expand Up @@ -1540,7 +1544,8 @@ public LoanProductRelatedDetail toLoanProductRelatedDetail() {
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.enableAccrualActivityPosting, this.supportedInterestRefundTypes);
this.loanScheduleProcessingType, this.fixedLength, this.enableAccrualActivityPosting, this.supportedInterestRefundTypes,
this.chargeOffBehaviour);
}

public Integer getLoanTermFrequency() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,5 +166,6 @@ public interface LoanProductConstants {

String ENABLE_ACCRUAL_ACTIVITY_POSTING = "enableAccrualActivityPosting";
String SUPPORTED_INTEREST_REFUND_TYPES = "supportedInterestRefundTypes";
String CHARGE_OFF_BEHAVIOUR = "chargeOffBehaviour";

}
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,8 @@ private RateData() {}
}

public List<String> supportedInterestRefundTypes;
@Schema(example = "REGULAR")
public String chargeOffBehaviour;
}

@Schema(description = "PostLoanProductsResponse")
Expand Down Expand Up @@ -604,6 +606,7 @@ private GetLoanProductsAccountingRule() {}
public Integer principalThresholdForLastInstalment;
public GetLoanProductsResponse.GetLoanProductsRepaymentStartDateType repaymentStartDateType;
public List<StringEnumOptionData> supportedInterestRefundTypes;
public StringEnumOptionData chargeOffBehaviour;
}

@Schema(description = "GetLoanProductsTemplateResponse")
Expand Down Expand Up @@ -1088,6 +1091,8 @@ private GetLoanProductsChargeOffReasonOptions() {}
public List<StringEnumOptionData> supportedInterestRefundTypes;
public List<StringEnumOptionData> supportedInterestRefundTypesOptions;
public List<GetLoanProductsChargeOffReasonOptions> chargeOffReasonOptions;
public StringEnumOptionData chargeOffBehaviour;
public List<StringEnumOptionData> chargeOffBehaviourOptions;
}

@Schema(description = "GetLoanProductsProductIdResponse")
Expand Down Expand Up @@ -1374,6 +1379,7 @@ private GetLoanCharge() {}
public Boolean enableAccrualActivityPosting;
public List<StringEnumOptionData> supportedInterestRefundTypes;
public List<GetLoanProductsTemplateResponse.GetLoanProductsChargeOffReasonOptions> chargeOffReasonOptions;
public StringEnumOptionData chargeOffBehaviour;
}

@Schema(description = "PutLoanProductsProductIdRequest")
Expand Down Expand Up @@ -1667,6 +1673,8 @@ private RateData() {}
}

public List<String> supportedInterestRefundTypes;
@Schema(example = "REGULAR")
public String chargeOffBehaviour;
}

public static final class AdvancedPaymentData {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import org.apache.fineract.portfolio.floatingrates.data.FloatingRateData;
import org.apache.fineract.portfolio.fund.data.FundData;
import org.apache.fineract.portfolio.loanaccount.data.LoanInterestRecalculationData;
import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeOffBehaviour;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
import org.apache.fineract.portfolio.loanproduct.domain.AllocationType;
Expand Down Expand Up @@ -137,6 +138,7 @@ public class LoanProductData implements Serializable {
private final Integer installmentAmountInMultiplesOf;
private final EnumOptionData repaymentStartDateType;
private final List<StringEnumOptionData> supportedInterestRefundTypes;
private final StringEnumOptionData chargeOffBehaviour;

// charges
private final Collection<ChargeData> charges;
Expand Down Expand Up @@ -195,6 +197,7 @@ public class LoanProductData implements Serializable {
private final List<FloatingRateData> floatingRateOptions;
private final List<EnumOptionData> repaymentStartDateTypeOptions;
private final List<StringEnumOptionData> supportedInterestRefundTypesOptions;
private final List<StringEnumOptionData> chargeOffBehaviourOptions;

private final Boolean multiDisburseLoan;
private final Integer maxTrancheCount;
Expand Down Expand Up @@ -333,6 +336,7 @@ public static LoanProductData lookup(final Long id, final String name, final Boo
final EnumOptionData loanScheduleProcessingTypeOptions = null;
final boolean enableAccrualActivityPosting = false;
final List<StringEnumOptionData> supportedInterestRefundTypes = null;
final StringEnumOptionData chargeOffBehaviour = null;

return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
Expand All @@ -353,7 +357,7 @@ public static LoanProductData lookup(final Long id, final String name, final Boo
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
paymentAllocation, creditAllocation, repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType,
loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes);
loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour);

}

Expand Down Expand Up @@ -455,6 +459,7 @@ public static LoanProductData lookupWithCurrency(final Long id, final String nam
final EnumOptionData loanScheduleProcessingType = null;
final boolean enableAccrualActivityPosting = false;
final List<StringEnumOptionData> supportedInterestRefundTypes = null;
final StringEnumOptionData chargeOffBehaviour = null;

return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
Expand All @@ -475,7 +480,7 @@ public static LoanProductData lookupWithCurrency(final Long id, final String nam
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
paymentAllocation, creditAllocation, repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType,
loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes);
loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour);

}

Expand Down Expand Up @@ -584,6 +589,7 @@ public static LoanProductData sensibleDefaultsForNewLoanProductCreation() {
final EnumOptionData loanScheduleProcessingType = LoanScheduleProcessingType.HORIZONTAL.asEnumOptionData();
final boolean enableAccrualActivityPosting = false;
final List<StringEnumOptionData> supportedInterestRefundTypes = null;
final StringEnumOptionData chargeOffBehaviour = LoanChargeOffBehaviour.REGULAR.getValueAsStringEnumOptionData();

return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
Expand All @@ -604,7 +610,7 @@ public static LoanProductData sensibleDefaultsForNewLoanProductCreation() {
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
paymentAllocation, creditAllocation, repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType,
loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes);
loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour);

}

Expand Down Expand Up @@ -707,6 +713,7 @@ public static LoanProductData loanProductWithFloatingRates(final Long id, final
final EnumOptionData loanScheduleProcessingType = null;
final boolean enableAccrualActivityPosting = false;
final List<StringEnumOptionData> supportedInterestRefundTypes = null;
final StringEnumOptionData chargeOffBehaviour = null;

return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
Expand All @@ -727,7 +734,7 @@ public static LoanProductData loanProductWithFloatingRates(final Long id, final
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
paymentAllocation, creditAllocationData, repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType,
loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes);
loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour);
}

public static LoanProductData withAccountingDetails(final LoanProductData productData, final Map<String, Object> accountingMappings,
Expand Down Expand Up @@ -778,7 +785,8 @@ public LoanProductData(final Long id, final String name, final String shortName,
final Collection<AdvancedPaymentData> paymentAllocation, final Collection<CreditAllocationData> creditAllocation,
final EnumOptionData repaymentStartDateType, final boolean enableInstallmentLevelDelinquency,
final EnumOptionData loanScheduleType, final EnumOptionData loanScheduleProcessingType, final Integer fixedLength,
final boolean enableAccrualActivityPosting, final List<StringEnumOptionData> supportedInterestRefundTypes) {
final boolean enableAccrualActivityPosting, final List<StringEnumOptionData> supportedInterestRefundTypes,
StringEnumOptionData chargeOffBehaviour) {
this.id = id;
this.name = name;
this.shortName = shortName;
Expand Down Expand Up @@ -918,6 +926,8 @@ public LoanProductData(final Long id, final String name, final String shortName,
this.enableAccrualActivityPosting = enableAccrualActivityPosting;
this.supportedInterestRefundTypes = supportedInterestRefundTypes;
this.supportedInterestRefundTypesOptions = null;
this.chargeOffBehaviour = chargeOffBehaviour;
this.chargeOffBehaviourOptions = null;
this.chargeOffReasonOptions = null;
}

Expand All @@ -941,7 +951,8 @@ public LoanProductData(final LoanProductData productData, final Collection<Charg
final List<EnumOptionData> advancedPaymentAllocationTypes, final List<EnumOptionData> loanScheduleTypeOptions,
final List<EnumOptionData> loanScheduleProcessingTypeOptions, final List<EnumOptionData> creditAllocationTransactionTypes,
final List<EnumOptionData> creditAllocationAllocationTypes,
final List<StringEnumOptionData> supportedInterestRefundTypesOptions, final List<CodeValueData> chargeOffReasonOptions) {
final List<StringEnumOptionData> supportedInterestRefundTypesOptions,
final List<StringEnumOptionData> chargeOffBehaviourOptions, final List<CodeValueData> chargeOffReasonOptions) {

this.id = productData.id;
this.name = productData.name;
Expand Down Expand Up @@ -1099,6 +1110,8 @@ public LoanProductData(final LoanProductData productData, final Collection<Charg
this.enableAccrualActivityPosting = productData.enableAccrualActivityPosting;
this.supportedInterestRefundTypesOptions = supportedInterestRefundTypesOptions;
this.supportedInterestRefundTypes = productData.supportedInterestRefundTypes;
this.chargeOffBehaviour = productData.chargeOffBehaviour;
this.chargeOffBehaviourOptions = chargeOffBehaviourOptions;
this.chargeOffReasonOptions = chargeOffReasonOptions;
}

Expand Down
Loading

0 comments on commit 390238e

Please sign in to comment.