FINERACT-2080: extracted json based workflows from Loan and other Loan related entities

This commit is contained in:
mark.vituska
2025-04-14 16:14:12 +02:00
committed by Adam Saghy
parent b4b2ef3701
commit f8d5bde921
23 changed files with 2136 additions and 1697 deletions
@@ -1233,7 +1233,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|| disbursementDetails.stream().anyMatch(it -> it.actualDisbursementDate() == null);
boolean isMultiDisburseLoanDisbursementAllowed = isMultiDisburmentLoan()
&& (disbursementDetails == null || disbursementDetails.stream().filter(it -> it.actualDisbursementDate() != null)
.count() < loanProduct.getLoanProductTrancheDetails().maxTrancheCount());
.count() < loanProduct.getLoanProductTrancheDetails().getMaxTrancheCount());
return isSingleDisburseLoanDisbursementAllowed || isMultiDisburseLoanDisbursementAllowed;
}
@@ -140,8 +140,8 @@ public class LoanInterestRecalculationDetails extends AbstractPersistableCustom<
loanProductInterestRecalculationDetails.getCompoundingFrequencyWeekday(),
loanProductInterestRecalculationDetails.getCompoundingFrequencyOnDay(),
loanProductInterestRecalculationDetails.getIsCompoundingToBePostedAsTransaction(),
loanProductInterestRecalculationDetails.allowCompoundingOnEod(),
loanProductInterestRecalculationDetails.disallowInterestCalculationOnPastDue(),
loanProductInterestRecalculationDetails.getAllowCompoundingOnEod(),
loanProductInterestRecalculationDetails.getDisallowInterestCalculationOnPastDue(),
loanProductInterestRecalculationDetails.getPreCloseInterestCalculationStrategy());
}
@@ -18,8 +18,6 @@
*/
package org.apache.fineract.portfolio.loanproduct.domain;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Embedded;
@@ -40,7 +38,6 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -48,10 +45,8 @@ import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.accounting.common.AccountingRuleType;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.infrastructure.core.domain.ExternalId;
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.portfolio.charge.domain.Charge;
@@ -65,7 +60,6 @@ import org.apache.fineract.portfolio.floatingrates.data.FloatingRatePeriodData;
import org.apache.fineract.portfolio.floatingrates.domain.FloatingRate;
import org.apache.fineract.portfolio.fund.domain.Fund;
import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeOffBehaviour;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.AprCalculator;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
@@ -234,267 +228,6 @@ public class LoanProduct extends AbstractPersistableCustom<Long> {
@Column(name = "repayment_start_date_type_enum", nullable = false)
private RepaymentStartDateType repaymentStartDateType;
public static LoanProduct assembleFromJson(final Fund fund, final String loanTransactionProcessingStrategy,
final List<Charge> productCharges, final JsonCommand command, final AprCalculator aprCalculator, FloatingRate floatingRate,
final List<Rate> productRates, List<LoanProductPaymentAllocationRule> loanProductPaymentAllocationRules,
List<LoanProductCreditAllocationRule> loanProductCreditAllocationRules) {
final String name = command.stringValueOfParameterNamed("name");
final String shortName = command.stringValueOfParameterNamed(LoanProductConstants.SHORT_NAME);
final String description = command.stringValueOfParameterNamed("description");
final String currencyCode = command.stringValueOfParameterNamed("currencyCode");
final Integer digitsAfterDecimal = command.integerValueOfParameterNamed("digitsAfterDecimal");
final Integer inMultiplesOf = command.integerValueOfParameterNamed("inMultiplesOf");
final MonetaryCurrency currency = new MonetaryCurrency(currencyCode, digitsAfterDecimal, inMultiplesOf);
final BigDecimal principal = command.bigDecimalValueOfParameterNamed("principal");
final BigDecimal minPrincipal = command.bigDecimalValueOfParameterNamed("minPrincipal");
final BigDecimal maxPrincipal = command.bigDecimalValueOfParameterNamed("maxPrincipal");
final InterestMethod interestMethod = InterestMethod.fromInt(command.integerValueOfParameterNamed("interestType"));
final InterestCalculationPeriodMethod interestCalculationPeriodMethod = InterestCalculationPeriodMethod
.fromInt(command.integerValueOfParameterNamed("interestCalculationPeriodType"));
final boolean allowPartialPeriodInterestCalcualtion = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ALLOW_PARTIAL_PERIOD_INTEREST_CALCUALTION_PARAM_NAME);
final AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.integerValueOfParameterNamed("amortizationType"));
final PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType
.fromInt(command.integerValueOfParameterNamed("repaymentFrequencyType"));
PeriodFrequencyType interestFrequencyType = PeriodFrequencyType.INVALID;
BigDecimal interestRatePerPeriod = null;
BigDecimal minInterestRatePerPeriod = null;
BigDecimal maxInterestRatePerPeriod = null;
BigDecimal annualInterestRate = null;
BigDecimal interestRateDifferential = null;
BigDecimal minDifferentialLendingRate = null;
BigDecimal maxDifferentialLendingRate = null;
BigDecimal defaultDifferentialLendingRate = null;
Boolean isFloatingInterestRateCalculationAllowed = null;
Integer minimumGapBetweenInstallments = null;
Integer maximumGapBetweenInstallments = null;
final Integer repaymentEvery = command.integerValueOfParameterNamed("repaymentEvery");
final Integer numberOfRepayments = command.integerValueOfParameterNamed("numberOfRepayments");
final Boolean isLinkedToFloatingInterestRates = command.booleanObjectValueOfParameterNamed("isLinkedToFloatingInterestRates");
if (isLinkedToFloatingInterestRates != null && isLinkedToFloatingInterestRates) {
interestRateDifferential = command.bigDecimalValueOfParameterNamed("interestRateDifferential");
minDifferentialLendingRate = command.bigDecimalValueOfParameterNamed("minDifferentialLendingRate");
maxDifferentialLendingRate = command.bigDecimalValueOfParameterNamed("maxDifferentialLendingRate");
defaultDifferentialLendingRate = command.bigDecimalValueOfParameterNamed("defaultDifferentialLendingRate");
isFloatingInterestRateCalculationAllowed = command
.booleanObjectValueOfParameterNamed("isFloatingInterestRateCalculationAllowed");
} else {
interestFrequencyType = PeriodFrequencyType.fromInt(command.integerValueOfParameterNamed("interestRateFrequencyType"));
interestRatePerPeriod = command.bigDecimalValueOfParameterNamed("interestRatePerPeriod");
minInterestRatePerPeriod = command.bigDecimalValueOfParameterNamed("minInterestRatePerPeriod");
maxInterestRatePerPeriod = command.bigDecimalValueOfParameterNamed("maxInterestRatePerPeriod");
annualInterestRate = aprCalculator.calculateFrom(interestFrequencyType, interestRatePerPeriod, numberOfRepayments,
repaymentEvery, repaymentFrequencyType);
}
final Boolean isVariableInstallmentsAllowed = command
.booleanObjectValueOfParameterNamed(LoanProductConstants.allowVariableInstallmentsParamName);
if (isVariableInstallmentsAllowed != null && isVariableInstallmentsAllowed) {
minimumGapBetweenInstallments = command.integerValueOfParameterNamed(LoanProductConstants.minimumGapBetweenInstallments);
maximumGapBetweenInstallments = command.integerValueOfParameterNamed(LoanProductConstants.maximumGapBetweenInstallments);
}
final Integer minNumberOfRepayments = command.integerValueOfParameterNamed("minNumberOfRepayments");
final Integer maxNumberOfRepayments = command.integerValueOfParameterNamed("maxNumberOfRepayments");
final BigDecimal inArrearsTolerance = command.bigDecimalValueOfParameterNamed("inArrearsTolerance");
// grace details
final Integer graceOnPrincipalPayment = command.integerValueOfParameterNamed("graceOnPrincipalPayment");
final Integer recurringMoratoriumOnPrincipalPeriods = command.integerValueOfParameterNamed("recurringMoratoriumOnPrincipalPeriods");
final Integer graceOnInterestPayment = command.integerValueOfParameterNamed("graceOnInterestPayment");
final Integer graceOnInterestCharged = command.integerValueOfParameterNamed("graceOnInterestCharged");
final Integer minimumDaysBetweenDisbursalAndFirstRepayment = command
.integerValueOfParameterNamed(LoanProductConstants.MINIMUM_DAYS_BETWEEN_DISBURSAL_AND_FIRST_REPAYMENT);
final AccountingRuleType accountingRuleType = AccountingRuleType.fromInt(command.integerValueOfParameterNamed("accountingRule"));
final boolean includeInBorrowerCycle = command.booleanPrimitiveValueOfParameterNamed("includeInBorrowerCycle");
final LocalDate startDate = command.localDateValueOfParameterNamed("startDate");
final LocalDate closeDate = command.localDateValueOfParameterNamed("closeDate");
final ExternalId externalId = ExternalIdFactory.produce(command.stringValueOfParameterNamedAllowingNull("externalId"));
final LoanScheduleType loanScheduleType;
if (command.hasParameter("loanScheduleType")) {
loanScheduleType = LoanScheduleType.valueOf(command.stringValueOfParameterNamed("loanScheduleType"));
} else {
// For backward compatibility
loanScheduleType = LoanScheduleType.CUMULATIVE;
}
final LoanScheduleProcessingType loanScheduleProcessingType;
if (LoanScheduleType.PROGRESSIVE.equals(loanScheduleType) && command.hasParameter("loanScheduleProcessingType")) {
loanScheduleProcessingType = LoanScheduleProcessingType
.valueOf(command.stringValueOfParameterNamed("loanScheduleProcessingType"));
} else {
// For backward compatibility
loanScheduleProcessingType = LoanScheduleProcessingType.HORIZONTAL;
}
final boolean useBorrowerCycle = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.USE_BORROWER_CYCLE_PARAMETER_NAME);
final Set<LoanProductBorrowerCycleVariations> loanProductBorrowerCycleVariations = new HashSet<>();
if (useBorrowerCycle) {
populateBorrowerCycleVariations(command, loanProductBorrowerCycleVariations);
}
final boolean multiDisburseLoan = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.MULTI_DISBURSE_LOAN_PARAMETER_NAME);
Integer maxTrancheCount = null;
BigDecimal outstandingLoanBalance = null;
if (multiDisburseLoan) {
outstandingLoanBalance = command.bigDecimalValueOfParameterNamed(LoanProductConstants.OUTSTANDING_LOAN_BALANCE_PARAMETER_NAME);
maxTrancheCount = command.integerValueOfParameterNamed(LoanProductConstants.MAX_TRANCHE_COUNT_PARAMETER_NAME);
}
final Integer graceOnArrearsAgeing = command
.integerValueOfParameterNamed(LoanProductConstants.GRACE_ON_ARREARS_AGEING_PARAMETER_NAME);
final Integer overdueDaysForNPA = command.integerValueOfParameterNamed(LoanProductConstants.OVERDUE_DAYS_FOR_NPA_PARAMETER_NAME);
// Interest recalculation settings
final boolean isInterestRecalculationEnabled = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.IS_INTEREST_RECALCULATION_ENABLED_PARAMETER_NAME);
final DaysInMonthType daysInMonthType = DaysInMonthType
.fromInt(command.integerValueOfParameterNamed(LoanProductConstants.DAYS_IN_MONTH_TYPE_PARAMETER_NAME));
final DaysInYearType daysInYearType = DaysInYearType
.fromInt(command.integerValueOfParameterNamed(LoanProductConstants.DAYS_IN_YEAR_TYPE_PARAMETER_NAME));
final DaysInYearCustomStrategyType daysInYearCustomStrategy = command.enumValueOfParameterNamed(
LoanProductConstants.DAYS_IN_YEAR_CUSTOM_STRATEGY_TYPE_PARAMETER_NAME, DaysInYearCustomStrategyType.class);
LoanProductInterestRecalculationDetails interestRecalculationSettings = null;
if (isInterestRecalculationEnabled) {
interestRecalculationSettings = LoanProductInterestRecalculationDetails.createFrom(command);
}
final boolean holdGuarantorFunds = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.holdGuaranteeFundsParamName);
LoanProductGuaranteeDetails loanProductGuaranteeDetails = null;
if (holdGuarantorFunds) {
loanProductGuaranteeDetails = LoanProductGuaranteeDetails.createFrom(command);
}
LoanProductConfigurableAttributes loanConfigurableAttributes = null;
if (command.parameterExists(LoanProductConstants.allowAttributeOverridesParamName)) {
loanConfigurableAttributes = LoanProductConfigurableAttributes.createFrom(command);
} else {
loanConfigurableAttributes = LoanProductConfigurableAttributes.populateDefaultsForConfigurableAttributes();
}
BigDecimal principalThresholdForLastInstallment = command
.bigDecimalValueOfParameterNamed(LoanProductConstants.principalThresholdForLastInstallmentParamName);
if (principalThresholdForLastInstallment == null) {
principalThresholdForLastInstallment = multiDisburseLoan
? LoanProductConstants.DEFAULT_PRINCIPAL_THRESHOLD_FOR_MULTI_DISBURSE_LOAN
: LoanProductConstants.DEFAULT_PRINCIPAL_THRESHOLD_FOR_SINGLE_DISBURSE_LOAN;
}
final boolean accountMovesOutOfNPAOnlyOnArrearsCompletion = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ACCOUNT_MOVES_OUT_OF_NPA_ONLY_ON_ARREARS_COMPLETION_PARAM_NAME);
final boolean canDefineEmiAmount = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.canDefineEmiAmountParamName);
final Integer installmentAmountInMultiplesOf = command
.integerValueOfParameterNamed(LoanProductConstants.installmentAmountInMultiplesOfParamName);
final boolean syncExpectedWithDisbursementDate = command.booleanPrimitiveValueOfParameterNamed("syncExpectedWithDisbursementDate");
final boolean canUseForTopup = command.parameterExists(LoanProductConstants.CAN_USE_FOR_TOPUP)
&& command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.CAN_USE_FOR_TOPUP);
final boolean isEqualAmortization = command.parameterExists(LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM)
&& command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM);
BigDecimal fixedPrincipalPercentagePerInstallment = command
.bigDecimalValueOfParameterNamed(LoanProductConstants.fixedPrincipalPercentagePerInstallmentParamName);
final boolean disallowExpectedDisbursements = command.parameterExists(LoanProductConstants.DISALLOW_EXPECTED_DISBURSEMENTS)
&& command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.DISALLOW_EXPECTED_DISBURSEMENTS);
final boolean allowApprovedDisbursedAmountsOverApplied = command
.parameterExists(LoanProductConstants.ALLOW_APPROVED_DISBURSED_AMOUNTS_OVER_APPLIED)
&& command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ALLOW_APPROVED_DISBURSED_AMOUNTS_OVER_APPLIED);
final String overAppliedCalculationType = command
.stringValueOfParameterNamedAllowingNull(LoanProductConstants.OVER_APPLIED_CALCULATION_TYPE);
final Integer overAppliedNumber = command.integerValueOfParameterNamed(LoanProductConstants.OVER_APPLIED_NUMBER);
final Integer dueDaysForRepaymentEvent = command.integerValueOfParameterNamed(LoanProductConstants.DUE_DAYS_FOR_REPAYMENT_EVENT);
final Integer overDueDaysForRepaymentEvent = command
.integerValueOfParameterNamed(LoanProductConstants.OVER_DUE_DAYS_FOR_REPAYMENT_EVENT);
final boolean enableDownPayment = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ENABLE_DOWN_PAYMENT);
final BigDecimal disbursedAmountPercentageDownPayment = command
.bigDecimalValueOfParameterNamed(LoanProductConstants.DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT);
final boolean enableAutoRepaymentForDownPayment = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT);
final RepaymentStartDateType repaymentStartDateType = RepaymentStartDateType
.fromInt(command.integerValueOfParameterNamed(LoanProductConstants.REPAYMENT_START_DATE_TYPE));
final boolean enableInstallmentLevelDelinquency = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY);
final Integer fixedLength = command.integerValueOfParameterNamed(LoanProductConstants.FIXED_LENGTH);
final boolean enableAccrualActivityPosting = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ENABLE_ACCRUAL_ACTIVITY_POSTING);
boolean interestRecognitionOnDisbursementDate = false;
if (command.parameterExists(LoanProductConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE)) {
interestRecognitionOnDisbursementDate = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE);
}
List<LoanSupportedInterestRefundTypes> supportedInterestRefundTypes = new ArrayList<>();
if (command.parameterExists(LoanProductConstants.SUPPORTED_INTEREST_REFUND_TYPES)) {
JsonArray supportedTransactionsForInterestRefund = command
.arrayOfParameterNamed(LoanProductConstants.SUPPORTED_INTEREST_REFUND_TYPES);
supportedTransactionsForInterestRefund.iterator().forEachRemaining(value -> {
supportedInterestRefundTypes.add(LoanSupportedInterestRefundTypes.valueOf(value.getAsString()));
});
}
final LoanChargeOffBehaviour chargeOffBehaviour;
if (command.parameterExists(LoanProductConstants.CHARGE_OFF_BEHAVIOUR)) {
chargeOffBehaviour = LoanChargeOffBehaviour
.valueOf(command.stringValueOfParameterNamed(LoanProductConstants.CHARGE_OFF_BEHAVIOUR));
} else {
// For backward compatibility
chargeOffBehaviour = LoanChargeOffBehaviour.REGULAR;
}
return new LoanProduct(fund, loanTransactionProcessingStrategy, loanProductPaymentAllocationRules, loanProductCreditAllocationRules,
name, shortName, description, currency, principal, minPrincipal, maxPrincipal, interestRatePerPeriod,
minInterestRatePerPeriod, maxInterestRatePerPeriod, interestFrequencyType, annualInterestRate, interestMethod,
interestCalculationPeriodMethod, allowPartialPeriodInterestCalcualtion, repaymentEvery, repaymentFrequencyType,
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, graceOnPrincipalPayment,
recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment, graceOnInterestCharged, amortizationMethod,
inArrearsTolerance, productCharges, accountingRuleType, includeInBorrowerCycle, startDate, closeDate, externalId,
useBorrowerCycle, loanProductBorrowerCycleVariations, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance,
graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
interestRecalculationSettings, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuarantorFunds,
loanProductGuaranteeDetails, principalThresholdForLastInstallment, accountMovesOutOfNPAOnlyOnArrearsCompletion,
canDefineEmiAmount, installmentAmountInMultiplesOf, loanConfigurableAttributes, isLinkedToFloatingInterestRates,
floatingRate, interestRateDifferential, minDifferentialLendingRate, maxDifferentialLendingRate,
defaultDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed,
minimumGapBetweenInstallments, maximumGapBetweenInstallments, syncExpectedWithDisbursementDate, canUseForTopup,
isEqualAmortization, productRates, fixedPrincipalPercentagePerInstallment, disallowExpectedDisbursements,
allowApprovedDisbursedAmountsOverApplied, overAppliedCalculationType, overAppliedNumber, dueDaysForRepaymentEvent,
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType, loanScheduleProcessingType, fixedLength,
enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour, interestRecognitionOnDisbursementDate,
daysInYearCustomStrategy);
}
public void updateLoanProductInRelatedClasses() {
if (this.isInterestRecalculationEnabled()) {
this.productInterestRecalculationDetails.updateProduct(this);
@@ -504,170 +237,6 @@ public class LoanProduct extends AbstractPersistableCustom<Long> {
}
}
private static void populateBorrowerCycleVariations(final JsonCommand command,
final Set<LoanProductBorrowerCycleVariations> loanProductBorrowerCycleVariations) {
assemblePrincipalVariations(command, loanProductBorrowerCycleVariations);
assembleRepaymentVariations(command, loanProductBorrowerCycleVariations);
assembleInterestRateVariations(command, loanProductBorrowerCycleVariations);
}
private static void assembleInterestRateVariations(final JsonCommand command,
final Set<LoanProductBorrowerCycleVariations> loanProductBorrowerCycleVariations) {
assembleVariations(command, loanProductBorrowerCycleVariations, LoanProductParamType.INTERESTRATE.getValue(),
LoanProductConstants.INTEREST_RATE_VARIATIONS_FOR_BORROWER_CYCLE_PARAMETER_NAME);
}
private static void assembleRepaymentVariations(final JsonCommand command,
final Set<LoanProductBorrowerCycleVariations> loanProductBorrowerCycleVariations) {
assembleVariations(command, loanProductBorrowerCycleVariations, LoanProductParamType.REPAYMENT.getValue(),
LoanProductConstants.NUMBER_OF_REPAYMENT_VARIATIONS_FOR_BORROWER_CYCLE_PARAMETER_NAME);
}
private static void assemblePrincipalVariations(final JsonCommand command,
final Set<LoanProductBorrowerCycleVariations> loanProductBorrowerCycleVariations) {
assembleVariations(command, loanProductBorrowerCycleVariations, LoanProductParamType.PRINCIPAL.getValue(),
LoanProductConstants.PRINCIPAL_VARIATIONS_FOR_BORROWER_CYCLE_PARAMETER_NAME);
}
private static void assembleVariations(final JsonCommand command,
final Set<LoanProductBorrowerCycleVariations> loanProductBorrowerCycleVariations, Integer paramType,
String variationParameterName) {
if (command.parameterExists(variationParameterName)) {
final JsonArray variationArray = command.arrayOfParameterNamed(variationParameterName);
if (variationArray != null && variationArray.size() > 0) {
int i = 0;
do {
final JsonObject jsonObject = variationArray.get(i).getAsJsonObject();
BigDecimal defaultValue = null;
BigDecimal minValue = null;
BigDecimal maxValue = null;
Integer cycleNumber = null;
Integer valueUsageCondition = null;
if (jsonObject.has(LoanProductConstants.DEFAULT_VALUE_PARAMETER_NAME)
&& jsonObject.get(LoanProductConstants.DEFAULT_VALUE_PARAMETER_NAME).isJsonPrimitive()) {
defaultValue = jsonObject.getAsJsonPrimitive(LoanProductConstants.DEFAULT_VALUE_PARAMETER_NAME).getAsBigDecimal();
}
if (jsonObject.has(LoanProductConstants.MIN_VALUE_PARAMETER_NAME)
&& jsonObject.get(LoanProductConstants.MIN_VALUE_PARAMETER_NAME).isJsonPrimitive()
&& StringUtils.isNotBlank(jsonObject.get(LoanProductConstants.MIN_VALUE_PARAMETER_NAME).getAsString())) {
minValue = jsonObject.getAsJsonPrimitive(LoanProductConstants.MIN_VALUE_PARAMETER_NAME).getAsBigDecimal();
}
if (jsonObject.has(LoanProductConstants.MAX_VALUE_PARAMETER_NAME)
&& jsonObject.get(LoanProductConstants.MAX_VALUE_PARAMETER_NAME).isJsonPrimitive()
&& StringUtils.isNotBlank(jsonObject.get(LoanProductConstants.MAX_VALUE_PARAMETER_NAME).getAsString())) {
maxValue = jsonObject.getAsJsonPrimitive(LoanProductConstants.MAX_VALUE_PARAMETER_NAME).getAsBigDecimal();
}
if (jsonObject.has(LoanProductConstants.BORROWER_CYCLE_NUMBER_PARAM_NAME)
&& jsonObject.get(LoanProductConstants.BORROWER_CYCLE_NUMBER_PARAM_NAME).isJsonPrimitive()) {
cycleNumber = jsonObject.getAsJsonPrimitive(LoanProductConstants.BORROWER_CYCLE_NUMBER_PARAM_NAME).getAsInt();
}
if (jsonObject.has(LoanProductConstants.VALUE_CONDITION_TYPE_PARAM_NAME)
&& jsonObject.get(LoanProductConstants.VALUE_CONDITION_TYPE_PARAM_NAME).isJsonPrimitive()) {
valueUsageCondition = jsonObject.getAsJsonPrimitive(LoanProductConstants.VALUE_CONDITION_TYPE_PARAM_NAME)
.getAsInt();
}
LoanProductBorrowerCycleVariations borrowerCycleVariations = new LoanProductBorrowerCycleVariations(cycleNumber,
paramType, valueUsageCondition, minValue, maxValue, defaultValue);
loanProductBorrowerCycleVariations.add(borrowerCycleVariations);
i++;
} while (i < variationArray.size());
}
}
}
private Map<String, Object> updateBorrowerCycleVariations(final JsonCommand command) {
final Map<String, Object> actualChanges = new LinkedHashMap<>(20);
List<Long> variationIds = fetchAllVariationIds();
updateBorrowerCycleVariations(command, LoanProductParamType.PRINCIPAL.getValue(),
LoanProductConstants.PRINCIPAL_VARIATIONS_FOR_BORROWER_CYCLE_PARAMETER_NAME, actualChanges, variationIds);
updateBorrowerCycleVariations(command, LoanProductParamType.INTERESTRATE.getValue(),
LoanProductConstants.INTEREST_RATE_VARIATIONS_FOR_BORROWER_CYCLE_PARAMETER_NAME, actualChanges, variationIds);
updateBorrowerCycleVariations(command, LoanProductParamType.REPAYMENT.getValue(),
LoanProductConstants.NUMBER_OF_REPAYMENT_VARIATIONS_FOR_BORROWER_CYCLE_PARAMETER_NAME, actualChanges, variationIds);
for (Long id : variationIds) {
this.borrowerCycleVariations.remove(fetchLoanProductBorrowerCycleVariationById(id));
}
return actualChanges;
}
private List<Long> fetchAllVariationIds() {
List<Long> list = new ArrayList<>();
for (LoanProductBorrowerCycleVariations cycleVariation : this.borrowerCycleVariations) {
list.add(cycleVariation.getId());
}
return list;
}
private void updateBorrowerCycleVariations(final JsonCommand command, Integer paramType, String variationParameterName,
final Map<String, Object> actualChanges, List<Long> variationIds) {
if (command.parameterExists(variationParameterName)) {
final JsonArray variationArray = command.arrayOfParameterNamed(variationParameterName);
if (variationArray != null && variationArray.size() > 0) {
int i = 0;
do {
final JsonObject jsonObject = variationArray.get(i).getAsJsonObject();
BigDecimal defaultValue = null;
BigDecimal minValue = null;
BigDecimal maxValue = null;
Integer cycleNumber = null;
Integer valueUsageCondition = null;
Long id = null;
if (jsonObject.has(LoanProductConstants.DEFAULT_VALUE_PARAMETER_NAME)
&& jsonObject.get(LoanProductConstants.DEFAULT_VALUE_PARAMETER_NAME).isJsonPrimitive()) {
defaultValue = jsonObject.getAsJsonPrimitive(LoanProductConstants.DEFAULT_VALUE_PARAMETER_NAME).getAsBigDecimal();
}
if (jsonObject.has(LoanProductConstants.MIN_VALUE_PARAMETER_NAME)
&& jsonObject.get(LoanProductConstants.MIN_VALUE_PARAMETER_NAME).isJsonPrimitive()
&& StringUtils.isNotBlank(jsonObject.get(LoanProductConstants.MIN_VALUE_PARAMETER_NAME).getAsString())) {
minValue = jsonObject.getAsJsonPrimitive(LoanProductConstants.MIN_VALUE_PARAMETER_NAME).getAsBigDecimal();
}
if (jsonObject.has(LoanProductConstants.MAX_VALUE_PARAMETER_NAME)
&& jsonObject.get(LoanProductConstants.MAX_VALUE_PARAMETER_NAME).isJsonPrimitive()
&& StringUtils.isNotBlank(jsonObject.get(LoanProductConstants.MAX_VALUE_PARAMETER_NAME).getAsString())) {
maxValue = jsonObject.getAsJsonPrimitive(LoanProductConstants.MAX_VALUE_PARAMETER_NAME).getAsBigDecimal();
}
if (jsonObject.has(LoanProductConstants.BORROWER_CYCLE_NUMBER_PARAM_NAME)
&& jsonObject.get(LoanProductConstants.BORROWER_CYCLE_NUMBER_PARAM_NAME).isJsonPrimitive()) {
cycleNumber = jsonObject.getAsJsonPrimitive(LoanProductConstants.BORROWER_CYCLE_NUMBER_PARAM_NAME).getAsInt();
}
if (jsonObject.has(LoanProductConstants.VALUE_CONDITION_TYPE_PARAM_NAME)
&& jsonObject.get(LoanProductConstants.VALUE_CONDITION_TYPE_PARAM_NAME).isJsonPrimitive()) {
valueUsageCondition = jsonObject.getAsJsonPrimitive(LoanProductConstants.VALUE_CONDITION_TYPE_PARAM_NAME)
.getAsInt();
}
if (jsonObject.has(LoanProductConstants.BORROWER_CYCLE_ID_PARAMETER_NAME)
&& jsonObject.get(LoanProductConstants.BORROWER_CYCLE_ID_PARAMETER_NAME).isJsonPrimitive() && StringUtils
.isNotBlank(jsonObject.get(LoanProductConstants.BORROWER_CYCLE_ID_PARAMETER_NAME).getAsString())) {
id = jsonObject.getAsJsonPrimitive(LoanProductConstants.BORROWER_CYCLE_ID_PARAMETER_NAME).getAsLong();
}
LoanProductBorrowerCycleVariations borrowerCycleVariations = new LoanProductBorrowerCycleVariations(cycleNumber,
paramType, valueUsageCondition, minValue, maxValue, defaultValue);
if (id == null) {
borrowerCycleVariations.updateLoanProduct(this);
this.borrowerCycleVariations.add(borrowerCycleVariations);
actualChanges.put("borrowerCycleParamType", paramType);
} else {
variationIds.remove(id);
LoanProductBorrowerCycleVariations existingCycleVariation = fetchLoanProductBorrowerCycleVariationById(id);
if (!existingCycleVariation.equals(borrowerCycleVariations)) {
existingCycleVariation.copy(borrowerCycleVariations);
actualChanges.put("borrowerCycleId", id);
}
}
i++;
} while (i < variationArray.size());
}
}
}
private void clearVariations() {
this.borrowerCycleVariations.clear();
}
public LoanProduct() {
this.loanProductRelatedDetail = null;
this.loanProductMinMaxConstraints = null;
@@ -951,456 +520,7 @@ public class LoanProduct extends AbstractPersistableCustom<Long> {
return updated;
}
public Map<String, Object> update(final JsonCommand command, final AprCalculator aprCalculator, FloatingRate floatingRate) {
final Map<String, Object> actualChanges = this.loanProductRelatedDetail.update(command, aprCalculator);
actualChanges.putAll(loanProductMinMaxConstraints().update(command));
final String isLinkedToFloatingInterestRates = "isLinkedToFloatingInterestRates";
if (command.isChangeInBooleanParameterNamed(isLinkedToFloatingInterestRates, this.isLinkedToFloatingInterestRate)) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(isLinkedToFloatingInterestRates);
actualChanges.put(isLinkedToFloatingInterestRates, newValue);
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();
this.loanProductMinMaxConstraints.updateForFloatingInterestRates();
} else {
this.floatingRates = null;
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.allowVariableInstallmentsParamName,
this.allowVariabeInstallments)) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.allowVariableInstallmentsParamName);
actualChanges.put(LoanProductConstants.allowVariableInstallmentsParamName, newValue);
this.allowVariabeInstallments = newValue;
}
if (this.allowVariabeInstallments) {
actualChanges.putAll(loanProductVariableInstallmentConfig().update(command));
} else {
this.variableInstallmentConfig = null;
}
final String accountingTypeParamName = "accountingRule";
Integer currentValue = this.accountingRule == null ? null : this.accountingRule.getValue();
if (command.isChangeInIntegerParameterNamed(accountingTypeParamName, currentValue)) {
final Integer newValue = command.integerValueOfParameterNamed(accountingTypeParamName);
actualChanges.put(accountingTypeParamName, newValue);
this.accountingRule = AccountingRuleType.fromInt(newValue);
}
final String nameParamName = "name";
if (command.isChangeInStringParameterNamed(nameParamName, this.name)) {
final String newValue = command.stringValueOfParameterNamed(nameParamName);
actualChanges.put(nameParamName, newValue);
this.name = newValue;
}
final String shortNameParamName = LoanProductConstants.SHORT_NAME;
if (command.isChangeInStringParameterNamed(shortNameParamName, this.shortName)) {
final String newValue = command.stringValueOfParameterNamed(shortNameParamName);
actualChanges.put(shortNameParamName, newValue);
this.shortName = newValue;
}
final String descriptionParamName = "description";
if (command.isChangeInStringParameterNamed(descriptionParamName, this.description)) {
final String newValue = command.stringValueOfParameterNamed(descriptionParamName);
actualChanges.put(descriptionParamName, newValue);
this.description = newValue;
}
Long existingFundId = null;
if (this.fund != null) {
existingFundId = this.fund.getId();
}
final String fundIdParamName = "fundId";
if (command.isChangeInLongParameterNamed(fundIdParamName, existingFundId)) {
final Long newValue = command.longValueOfParameterNamed(fundIdParamName);
actualChanges.put(fundIdParamName, newValue);
}
final String transactionProcessingStrategyCodeParamName = "transactionProcessingStrategyCode";
if (command.isChangeInStringParameterNamed(transactionProcessingStrategyCodeParamName, this.transactionProcessingStrategyCode)) {
final String newValue = command.stringValueOfParameterNamed(transactionProcessingStrategyCodeParamName);
actualChanges.put(transactionProcessingStrategyCodeParamName, newValue);
}
final String paymentAllocationParamName = "paymentAllocation";
if (command.hasParameter(paymentAllocationParamName)) {
final JsonArray jsonArray = command.arrayOfParameterNamed(paymentAllocationParamName);
if (jsonArray != null) {
actualChanges.put(paymentAllocationParamName, command.jsonFragment(paymentAllocationParamName));
}
}
final String creditAllocationParamName = "creditAllocation";
if (command.hasParameter(creditAllocationParamName)) {
final JsonArray jsonArray = command.arrayOfParameterNamed(creditAllocationParamName);
if (jsonArray != null) {
actualChanges.put(creditAllocationParamName, command.jsonFragment(creditAllocationParamName));
}
}
final String chargesParamName = "charges";
if (command.hasParameter(chargesParamName)) {
final JsonArray jsonArray = command.arrayOfParameterNamed(chargesParamName);
if (jsonArray != null) {
actualChanges.put(chargesParamName, command.jsonFragment(chargesParamName));
}
}
final String includeInBorrowerCycleParamName = "includeInBorrowerCycle";
if (command.isChangeInBooleanParameterNamed(includeInBorrowerCycleParamName, this.includeInBorrowerCycle)) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(includeInBorrowerCycleParamName);
actualChanges.put(includeInBorrowerCycleParamName, newValue);
this.includeInBorrowerCycle = newValue;
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.USE_BORROWER_CYCLE_PARAMETER_NAME, this.useBorrowerCycle)) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.USE_BORROWER_CYCLE_PARAMETER_NAME);
actualChanges.put(LoanProductConstants.USE_BORROWER_CYCLE_PARAMETER_NAME, newValue);
this.useBorrowerCycle = newValue;
}
if (this.useBorrowerCycle) {
actualChanges.putAll(updateBorrowerCycleVariations(command));
} else {
clearVariations();
}
final String dateFormatAsInput = command.dateFormat();
final String localeAsInput = command.locale();
final String localeParamName = "locale";
final String dateFormatParamName = "dateFormat";
final String startDateParamName = "startDate";
if (command.isChangeInLocalDateParameterNamed(startDateParamName, getStartDate())) {
final String valueAsInput = command.stringValueOfParameterNamed(startDateParamName);
actualChanges.put(startDateParamName, valueAsInput);
actualChanges.put(dateFormatParamName, dateFormatAsInput);
actualChanges.put(localeParamName, localeAsInput);
this.startDate = command.localDateValueOfParameterNamed(startDateParamName);
}
final String closeDateParamName = "closeDate";
if (command.isChangeInLocalDateParameterNamed(closeDateParamName, getCloseDate())) {
final String valueAsInput = command.stringValueOfParameterNamed(closeDateParamName);
actualChanges.put(closeDateParamName, valueAsInput);
actualChanges.put(dateFormatParamName, dateFormatAsInput);
actualChanges.put(localeParamName, localeAsInput);
this.closeDate = command.localDateValueOfParameterNamed(closeDateParamName);
}
final String externalIdTypeParamName = "externalId";
if (command.isChangeInExternalIdParameterNamed(externalIdTypeParamName, this.externalId)) {
final ExternalId newValue = ExternalIdFactory.produce(command.stringValueOfParameterNamed(externalIdTypeParamName));
actualChanges.put(accountingTypeParamName, newValue);
this.externalId = newValue;
}
loanProductTrancheDetails.update(command, actualChanges, localeAsInput);
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.OVERDUE_DAYS_FOR_NPA_PARAMETER_NAME, this.overdueDaysForNPA)) {
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.OVERDUE_DAYS_FOR_NPA_PARAMETER_NAME);
actualChanges.put(LoanProductConstants.OVERDUE_DAYS_FOR_NPA_PARAMETER_NAME, newValue);
actualChanges.put("locale", localeAsInput);
this.overdueDaysForNPA = newValue;
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.MINIMUM_DAYS_BETWEEN_DISBURSAL_AND_FIRST_REPAYMENT,
this.minimumDaysBetweenDisbursalAndFirstRepayment)) {
final Integer newValue = command
.integerValueOfParameterNamed(LoanProductConstants.MINIMUM_DAYS_BETWEEN_DISBURSAL_AND_FIRST_REPAYMENT);
actualChanges.put(LoanProductConstants.MINIMUM_DAYS_BETWEEN_DISBURSAL_AND_FIRST_REPAYMENT, newValue);
actualChanges.put("locale", localeAsInput);
this.minimumDaysBetweenDisbursalAndFirstRepayment = newValue;
}
if (command.isChangeInBooleanParameterNamed("syncExpectedWithDisbursementDate", this.syncExpectedWithDisbursementDate)) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed("syncExpectedWithDisbursementDate");
actualChanges.put("syncExpectedWithDisbursementDate", newValue);
this.syncExpectedWithDisbursementDate = newValue;
}
Long delinquencyBucketId = null;
if (this.delinquencyBucket != null) {
delinquencyBucketId = this.delinquencyBucket.getId();
}
if (command.isChangeInLongParameterNamed(LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME, delinquencyBucketId)) {
final Long newValue = command.longValueOfParameterNamed(LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME);
actualChanges.put(LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME, newValue);
}
// Update interest recalculation settings
final boolean isInterestRecalculationEnabledChanged = actualChanges
.containsKey(LoanProductConstants.IS_INTEREST_RECALCULATION_ENABLED_PARAMETER_NAME);
if (isInterestRecalculationEnabledChanged) {
if (this.isInterestRecalculationEnabled()) {
this.productInterestRecalculationDetails = LoanProductInterestRecalculationDetails.createFrom(command);
this.productInterestRecalculationDetails.updateProduct(this);
actualChanges.put(LoanProductConstants.interestRecalculationCompoundingMethodParameterName,
command.integerValueOfParameterNamed(LoanProductConstants.interestRecalculationCompoundingMethodParameterName));
actualChanges.put(LoanProductConstants.rescheduleStrategyMethodParameterName,
command.integerValueOfParameterNamed(LoanProductConstants.rescheduleStrategyMethodParameterName));
} else {
this.productInterestRecalculationDetails = null;
}
}
if (!isInterestRecalculationEnabledChanged && this.isInterestRecalculationEnabled()) {
this.productInterestRecalculationDetails.update(command, actualChanges, localeAsInput);
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.holdGuaranteeFundsParamName, this.holdGuaranteeFunds)) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.holdGuaranteeFundsParamName);
actualChanges.put(LoanProductConstants.holdGuaranteeFundsParamName, newValue);
this.holdGuaranteeFunds = newValue;
}
final String configurableAttributesChanges = LoanProductConstants.allowAttributeOverridesParamName;
if (command.hasParameter(configurableAttributesChanges)) {
if (!command.parsedJson().getAsJsonObject().getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.isJsonNull()) {
actualChanges.put(configurableAttributesChanges, command.jsonFragment(configurableAttributesChanges));
if (command.parsedJson().getAsJsonObject().getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.amortizationTypeParamName)
.getAsBoolean() != this.loanConfigurableAttributes.getAmortizationBoolean()) {
this.loanConfigurableAttributes.setAmortizationType(
command.parsedJson().getAsJsonObject().getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.amortizationTypeParamName).getAsBoolean());
}
if (command.parsedJson().getAsJsonObject().getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.interestTypeParamName)
.getAsBoolean() != this.loanConfigurableAttributes.getInterestMethodBoolean()) {
this.loanConfigurableAttributes.setInterestType(
command.parsedJson().getAsJsonObject().getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.interestTypeParamName).getAsBoolean());
}
if (command.parsedJson().getAsJsonObject().getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.transactionProcessingStrategyCodeParamName)
.getAsBoolean() != this.loanConfigurableAttributes.getTransactionProcessingStrategyBoolean()) {
this.loanConfigurableAttributes.setTransactionProcessingStrategyCode(
command.parsedJson().getAsJsonObject().getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.transactionProcessingStrategyCodeParamName).getAsBoolean());
}
if (command.parsedJson().getAsJsonObject().getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.interestCalculationPeriodTypeParamName)
.getAsBoolean() != this.loanConfigurableAttributes.getInterestCalcPeriodBoolean()) {
this.loanConfigurableAttributes.setInterestCalculationPeriodType(
command.parsedJson().getAsJsonObject().getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.interestCalculationPeriodTypeParamName).getAsBoolean());
}
if (command.parsedJson().getAsJsonObject().getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.inArrearsToleranceParamName)
.getAsBoolean() != this.loanConfigurableAttributes.getArrearsToleranceBoolean()) {
this.loanConfigurableAttributes.setInArrearsTolerance(
command.parsedJson().getAsJsonObject().getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.inArrearsToleranceParamName).getAsBoolean());
}
if (command.parsedJson().getAsJsonObject().getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.repaymentEveryParamName)
.getAsBoolean() != this.loanConfigurableAttributes.getRepaymentEveryBoolean()) {
this.loanConfigurableAttributes.setRepaymentEvery(
command.parsedJson().getAsJsonObject().getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.repaymentEveryParamName).getAsBoolean());
}
if (command.parsedJson().getAsJsonObject().getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.graceOnPrincipalAndInterestPaymentParamName)
.getAsBoolean() != this.loanConfigurableAttributes.getGraceOnPrincipalAndInterestPaymentBoolean()) {
this.loanConfigurableAttributes.setGraceOnPrincipalAndInterestPayment(
command.parsedJson().getAsJsonObject().getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.graceOnPrincipalAndInterestPaymentParamName).getAsBoolean());
}
if (command.parsedJson().getAsJsonObject().getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.GRACE_ON_ARREARS_AGEING_PARAMETER_NAME)
.getAsBoolean() != this.loanConfigurableAttributes.getGraceOnArrearsAgingBoolean()) {
this.loanConfigurableAttributes.setGraceOnArrearsAgeing(
command.parsedJson().getAsJsonObject().getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.GRACE_ON_ARREARS_AGEING_PARAMETER_NAME).getAsBoolean());
}
} else {
this.loanConfigurableAttributes = LoanProductConfigurableAttributes.populateDefaultsForConfigurableAttributes();
this.loanConfigurableAttributes.updateLoanProduct(this);
}
}
if (actualChanges.containsKey(LoanProductConstants.holdGuaranteeFundsParamName)) {
if (this.holdGuaranteeFunds) {
this.loanProductGuaranteeDetails = LoanProductGuaranteeDetails.createFrom(command);
this.loanProductGuaranteeDetails.updateProduct(this);
actualChanges.put(LoanProductConstants.mandatoryGuaranteeParamName,
this.loanProductGuaranteeDetails.getMandatoryGuarantee());
actualChanges.put(LoanProductConstants.minimumGuaranteeFromGuarantorParamName,
this.loanProductGuaranteeDetails.getMinimumGuaranteeFromGuarantor());
actualChanges.put(LoanProductConstants.minimumGuaranteeFromOwnFundsParamName,
this.loanProductGuaranteeDetails.getMinimumGuaranteeFromOwnFunds());
} else {
this.loanProductGuaranteeDetails = null;
}
} else if (this.holdGuaranteeFunds) {
this.loanProductGuaranteeDetails.update(command, actualChanges);
}
if (command.isChangeInBigDecimalParameterNamed(LoanProductConstants.principalThresholdForLastInstallmentParamName,
this.principalThresholdForLastInstallment)) {
BigDecimal newValue = command
.bigDecimalValueOfParameterNamed(LoanProductConstants.principalThresholdForLastInstallmentParamName);
actualChanges.put(LoanProductConstants.principalThresholdForLastInstallmentParamName, newValue);
this.principalThresholdForLastInstallment = newValue;
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.ACCOUNT_MOVES_OUT_OF_NPA_ONLY_ON_ARREARS_COMPLETION_PARAM_NAME,
this.accountMovesOutOfNPAOnlyOnArrearsCompletion)) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(
LoanProductConstants.ACCOUNT_MOVES_OUT_OF_NPA_ONLY_ON_ARREARS_COMPLETION_PARAM_NAME);
actualChanges.put(LoanProductConstants.ACCOUNT_MOVES_OUT_OF_NPA_ONLY_ON_ARREARS_COMPLETION_PARAM_NAME, newValue);
this.accountMovesOutOfNPAOnlyOnArrearsCompletion = newValue;
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.canDefineEmiAmountParamName, this.canDefineInstallmentAmount)) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.canDefineEmiAmountParamName);
actualChanges.put(LoanProductConstants.canDefineEmiAmountParamName, newValue);
this.canDefineInstallmentAmount = newValue;
}
if (command.isChangeInIntegerParameterNamedWithNullCheck(LoanProductConstants.installmentAmountInMultiplesOfParamName,
this.installmentAmountInMultiplesOf)) {
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.installmentAmountInMultiplesOfParamName);
actualChanges.put(LoanProductConstants.installmentAmountInMultiplesOfParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.installmentAmountInMultiplesOf = newValue;
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.CAN_USE_FOR_TOPUP, this.canUseForTopup)) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.CAN_USE_FOR_TOPUP);
actualChanges.put(LoanProductConstants.CAN_USE_FOR_TOPUP, newValue);
this.canUseForTopup = newValue;
}
if (command.hasParameter(LoanProductConstants.RATES_PARAM_NAME)) {
final JsonArray jsonArray = command.arrayOfParameterNamed(LoanProductConstants.RATES_PARAM_NAME);
if (jsonArray != null) {
actualChanges.put(LoanProductConstants.RATES_PARAM_NAME, command.jsonFragment(LoanProductConstants.RATES_PARAM_NAME));
}
}
if (command.isChangeInBigDecimalParameterNamed(LoanProductConstants.fixedPrincipalPercentagePerInstallmentParamName,
this.fixedPrincipalPercentagePerInstallment)) {
BigDecimal newValue = command
.bigDecimalValueOfParameterNamed(LoanProductConstants.fixedPrincipalPercentagePerInstallmentParamName);
actualChanges.put(LoanProductConstants.fixedPrincipalPercentagePerInstallmentParamName, newValue);
this.fixedPrincipalPercentagePerInstallment = newValue;
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.DISALLOW_EXPECTED_DISBURSEMENTS,
this.disallowExpectedDisbursements)) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.DISALLOW_EXPECTED_DISBURSEMENTS);
actualChanges.put(LoanProductConstants.DISALLOW_EXPECTED_DISBURSEMENTS, newValue);
this.disallowExpectedDisbursements = newValue;
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.ALLOW_APPROVED_DISBURSED_AMOUNTS_OVER_APPLIED,
this.allowApprovedDisbursedAmountsOverApplied)) {
final boolean newValue = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ALLOW_APPROVED_DISBURSED_AMOUNTS_OVER_APPLIED);
actualChanges.put(LoanProductConstants.ALLOW_APPROVED_DISBURSED_AMOUNTS_OVER_APPLIED, newValue);
this.allowApprovedDisbursedAmountsOverApplied = newValue;
}
if (command.isChangeInStringParameterNamed(LoanProductConstants.OVER_APPLIED_CALCULATION_TYPE, this.overAppliedCalculationType)) {
final String newValue = command.stringValueOfParameterNamed(LoanProductConstants.OVER_APPLIED_CALCULATION_TYPE);
actualChanges.put(LoanProductConstants.OVER_APPLIED_CALCULATION_TYPE, newValue);
this.overAppliedCalculationType = newValue;
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.OVER_APPLIED_NUMBER, this.overAppliedNumber)) {
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.OVER_APPLIED_NUMBER);
actualChanges.put(LoanProductConstants.OVER_APPLIED_NUMBER, newValue);
actualChanges.put("locale", localeAsInput);
this.overAppliedNumber = newValue;
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.DUE_DAYS_FOR_REPAYMENT_EVENT, this.dueDaysForRepaymentEvent)) {
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.DUE_DAYS_FOR_REPAYMENT_EVENT);
actualChanges.put(LoanProductConstants.DUE_DAYS_FOR_REPAYMENT_EVENT, newValue);
actualChanges.put("locale", localeAsInput);
this.dueDaysForRepaymentEvent = newValue;
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.OVER_DUE_DAYS_FOR_REPAYMENT_EVENT,
this.overDueDaysForRepaymentEvent)) {
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.OVER_DUE_DAYS_FOR_REPAYMENT_EVENT);
actualChanges.put(LoanProductConstants.OVER_DUE_DAYS_FOR_REPAYMENT_EVENT, newValue);
actualChanges.put("locale", localeAsInput);
this.overDueDaysForRepaymentEvent = newValue;
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.ENABLE_DOWN_PAYMENT,
this.loanProductRelatedDetail.isEnableDownPayment())) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ENABLE_DOWN_PAYMENT);
actualChanges.put(LoanProductConstants.ENABLE_DOWN_PAYMENT, newValue);
this.loanProductRelatedDetail.setEnableDownPayment(newValue);
}
if (command.isChangeInBigDecimalParameterNamed(LoanProductConstants.DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT,
this.loanProductRelatedDetail.getDisbursedAmountPercentageForDownPayment())) {
BigDecimal newValue = command.bigDecimalValueOfParameterNamed(LoanProductConstants.DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT);
actualChanges.put(LoanProductConstants.DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT, newValue);
this.loanProductRelatedDetail.setDisbursedAmountPercentageForDownPayment(newValue);
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT,
this.loanProductRelatedDetail.isEnableAutoRepaymentForDownPayment())) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT);
actualChanges.put(LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT, newValue);
this.loanProductRelatedDetail.setEnableAutoRepaymentForDownPayment(newValue);
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.REPAYMENT_START_DATE_TYPE,
this.repaymentStartDateType.getValue())) {
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.REPAYMENT_START_DATE_TYPE);
actualChanges.put(LoanProductConstants.REPAYMENT_START_DATE_TYPE, newValue);
this.repaymentStartDateType = RepaymentStartDateType.fromInt(newValue);
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY,
this.isEnableInstallmentLevelDelinquency())) {
final boolean newValue = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY);
actualChanges.put(LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY, newValue);
this.updateEnableInstallmentLevelDelinquency(newValue);
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.FIXED_LENGTH, loanProductRelatedDetail.getFixedLength())) {
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.FIXED_LENGTH);
actualChanges.put(LoanProductConstants.FIXED_LENGTH, newValue);
loanProductRelatedDetail.setFixedLength(newValue);
}
return actualChanges;
}
private LoanProductFloatingRates loanProductFloatingRates() {
public LoanProductFloatingRates loanProductFloatingRates() {
this.floatingRates = this.floatingRates == null ? new LoanProductFloatingRates(null, this, null, null, null, null, false)
: this.floatingRates;
return this.floatingRates;
@@ -1483,11 +603,11 @@ public class LoanProduct extends AbstractPersistableCustom<Long> {
}
public BigDecimal outstandingLoanBalance() {
return this.loanProductTrancheDetails.outstandingLoanBalance();
return this.loanProductTrancheDetails.getOutstandingLoanBalance();
}
public Integer maxTrancheCount() {
return this.loanProductTrancheDetails.maxTrancheCount();
return this.loanProductTrancheDetails.getMaxTrancheCount();
}
public boolean isInterestRecalculationEnabled() {
@@ -1498,17 +618,6 @@ public class LoanProduct extends AbstractPersistableCustom<Long> {
return this.minimumDaysBetweenDisbursalAndFirstRepayment == null ? 0 : this.minimumDaysBetweenDisbursalAndFirstRepayment;
}
public LoanProductBorrowerCycleVariations fetchLoanProductBorrowerCycleVariationById(Long id) {
LoanProductBorrowerCycleVariations borrowerCycleVariation = null;
for (LoanProductBorrowerCycleVariations cycleVariation : this.borrowerCycleVariations) {
if (id.equals(cycleVariation.getId())) {
borrowerCycleVariation = cycleVariation;
break;
}
}
return borrowerCycleVariation;
}
public Map<String, BigDecimal> fetchBorrowerCycleVariationsForCycleNumber(final Integer cycleNumber) {
Map<String, BigDecimal> borrowerCycleVariations = new HashMap<>();
borrowerCycleVariations.put(LoanProductConstants.PRINCIPAL, this.loanProductRelatedDetail.getPrincipal().getAmount());
@@ -26,14 +26,15 @@ import jakarta.persistence.OneToOne;
import jakarta.persistence.Table;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import lombok.Getter;
import lombok.Setter;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO;
import org.apache.fineract.portfolio.floatingrates.data.FloatingRatePeriodData;
import org.apache.fineract.portfolio.floatingrates.domain.FloatingRate;
@Setter
@Getter
@Entity
@Table(name = "m_product_loan_floating_rates")
public class LoanProductFloatingRates extends AbstractPersistableCustom<Long> {
@@ -77,80 +78,6 @@ public class LoanProductFloatingRates extends AbstractPersistableCustom<Long> {
this.isFloatingInterestRateCalculationAllowed = isFloatingInterestRateCalculationAllowed;
}
public LoanProduct getLoanProduct() {
return this.loanProduct;
}
public FloatingRate getFloatingRate() {
return this.floatingRate;
}
public BigDecimal getInterestRateDifferential() {
return this.interestRateDifferential;
}
public BigDecimal getMinDifferentialLendingRate() {
return this.minDifferentialLendingRate;
}
public BigDecimal getDefaultDifferentialLendingRate() {
return this.defaultDifferentialLendingRate;
}
public BigDecimal getMaxDifferentialLendingRate() {
return this.maxDifferentialLendingRate;
}
public boolean isFloatingInterestRateCalculationAllowed() {
return this.isFloatingInterestRateCalculationAllowed;
}
public Map<? extends String, ?> update(JsonCommand command, FloatingRate floatingRate) {
final Map<String, Object> actualChanges = new LinkedHashMap<>(20);
if (floatingRate != null) {
final String floatingRatesId = "floatingRatesId";
if (this.floatingRate == null || command.isChangeInLongParameterNamed(floatingRatesId, this.floatingRate.getId())) {
final long newValue = command.longValueOfParameterNamed(floatingRatesId);
actualChanges.put(floatingRatesId, newValue);
this.floatingRate = floatingRate;
}
}
final String interestRateDifferential = "interestRateDifferential";
if (command.isChangeInBigDecimalParameterNamed(interestRateDifferential, this.interestRateDifferential)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(interestRateDifferential);
actualChanges.put(interestRateDifferential, newValue);
this.interestRateDifferential = newValue;
}
final String minDifferentialLendingRate = "minDifferentialLendingRate";
if (command.isChangeInBigDecimalParameterNamed(minDifferentialLendingRate, this.minDifferentialLendingRate)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(minDifferentialLendingRate);
actualChanges.put(minDifferentialLendingRate, newValue);
this.minDifferentialLendingRate = newValue;
}
final String defaultDifferentialLendingRate = "defaultDifferentialLendingRate";
if (command.isChangeInBigDecimalParameterNamed(defaultDifferentialLendingRate, this.defaultDifferentialLendingRate)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(defaultDifferentialLendingRate);
actualChanges.put(defaultDifferentialLendingRate, newValue);
this.defaultDifferentialLendingRate = newValue;
}
final String maxDifferentialLendingRate = "maxDifferentialLendingRate";
if (command.isChangeInBigDecimalParameterNamed(maxDifferentialLendingRate, this.maxDifferentialLendingRate)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(maxDifferentialLendingRate);
actualChanges.put(maxDifferentialLendingRate, newValue);
this.maxDifferentialLendingRate = newValue;
}
final String isFloatingInterestRateCalculationAllowed = "isFloatingInterestRateCalculationAllowed";
if (command.isChangeInBooleanParameterNamed(isFloatingInterestRateCalculationAllowed,
this.isFloatingInterestRateCalculationAllowed)) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(isFloatingInterestRateCalculationAllowed);
actualChanges.put(isFloatingInterestRateCalculationAllowed, newValue);
this.isFloatingInterestRateCalculationAllowed = newValue;
}
return actualChanges;
}
public Collection<FloatingRatePeriodData> fetchInterestRates(final FloatingRateDTO floatingRateDTO) {
floatingRateDTO.addInterestRateDiff(this.interestRateDifferential);
return floatingRate.fetchInterestRates(floatingRateDTO);
@@ -24,10 +24,9 @@ import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToOne;
import jakarta.persistence.Table;
import java.math.BigDecimal;
import java.util.Map;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import lombok.Getter;
import lombok.Setter;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
/**
* Entity for capturing interest recalculation settings
@@ -35,6 +34,8 @@ import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
* @author conflux
*/
@Getter
@Setter
@Entity
@Table(name = "m_product_loan_guarantee_details")
public class LoanProductGuaranteeDetails extends AbstractPersistableCustom<Long> {
@@ -56,18 +57,7 @@ public class LoanProductGuaranteeDetails extends AbstractPersistableCustom<Long>
//
}
public static LoanProductGuaranteeDetails createFrom(final JsonCommand command) {
final BigDecimal mandatoryGuarantee = command.bigDecimalValueOfParameterNamed(LoanProductConstants.mandatoryGuaranteeParamName);
final BigDecimal minimumGuaranteeFromGuarantor = command
.bigDecimalValueOfParameterNamed(LoanProductConstants.minimumGuaranteeFromGuarantorParamName);
final BigDecimal minimumGuaranteeFromOwnFunds = command
.bigDecimalValueOfParameterNamed(LoanProductConstants.minimumGuaranteeFromOwnFundsParamName);
return new LoanProductGuaranteeDetails(mandatoryGuarantee, minimumGuaranteeFromOwnFunds, minimumGuaranteeFromGuarantor);
}
private LoanProductGuaranteeDetails(final BigDecimal mandatoryGuarantee, final BigDecimal minimumGuaranteeFromOwnFunds,
public LoanProductGuaranteeDetails(final BigDecimal mandatoryGuarantee, final BigDecimal minimumGuaranteeFromOwnFunds,
final BigDecimal minimumGuaranteeFromGuarantor) {
this.mandatoryGuarantee = mandatoryGuarantee;
this.minimumGuaranteeFromGuarantor = minimumGuaranteeFromGuarantor;
@@ -78,41 +68,4 @@ public class LoanProductGuaranteeDetails extends AbstractPersistableCustom<Long>
this.loanProduct = loanProduct;
}
public void update(final JsonCommand command, final Map<String, Object> actualChanges) {
if (command.isChangeInBigDecimalParameterNamed(LoanProductConstants.mandatoryGuaranteeParamName, this.mandatoryGuarantee)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(LoanProductConstants.mandatoryGuaranteeParamName);
actualChanges.put(LoanProductConstants.mandatoryGuaranteeParamName, newValue);
this.mandatoryGuarantee = newValue;
}
if (command.isChangeInBigDecimalParameterNamed(LoanProductConstants.minimumGuaranteeFromGuarantorParamName,
this.minimumGuaranteeFromGuarantor)) {
final BigDecimal newValue = command
.bigDecimalValueOfParameterNamed(LoanProductConstants.minimumGuaranteeFromGuarantorParamName);
actualChanges.put(LoanProductConstants.minimumGuaranteeFromGuarantorParamName, newValue);
this.minimumGuaranteeFromGuarantor = newValue;
}
if (command.isChangeInBigDecimalParameterNamed(LoanProductConstants.minimumGuaranteeFromOwnFundsParamName,
this.minimumGuaranteeFromOwnFunds)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(LoanProductConstants.minimumGuaranteeFromOwnFundsParamName);
actualChanges.put(LoanProductConstants.minimumGuaranteeFromOwnFundsParamName, newValue);
this.minimumGuaranteeFromOwnFunds = newValue;
}
}
public BigDecimal getMandatoryGuarantee() {
return this.mandatoryGuarantee;
}
public BigDecimal getMinimumGuaranteeFromOwnFunds() {
return this.minimumGuaranteeFromOwnFunds;
}
public BigDecimal getMinimumGuaranteeFromGuarantor() {
return this.minimumGuaranteeFromGuarantor;
}
}
@@ -23,10 +23,9 @@ import jakarta.persistence.Entity;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToOne;
import jakarta.persistence.Table;
import java.util.Map;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import lombok.Getter;
import lombok.Setter;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
/**
* Entity for capturing interest recalculation settings
@@ -34,6 +33,8 @@ import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
* @author conflux
*/
@Getter
@Setter
@Entity
@Table(name = "m_product_loan_recalculation_details")
public class LoanProductInterestRecalculationDetails extends AbstractPersistableCustom<Long> {
@@ -103,79 +104,7 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
//
}
public static LoanProductInterestRecalculationDetails createFrom(final JsonCommand command) {
final Integer interestRecalculationCompoundingMethod = InterestRecalculationCompoundingMethod
.fromInt(command.integerValueOfParameterNamed(LoanProductConstants.interestRecalculationCompoundingMethodParameterName))
.getValue();
final Integer loanRescheduleStrategyMethod = LoanRescheduleStrategyMethod
.fromInt(command.integerValueOfParameterNamed(LoanProductConstants.rescheduleStrategyMethodParameterName)).getValue();
final Integer recurrenceFrequency = command
.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyTypeParameterName);
final Integer recurrenceOnNthDay = command
.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyNthDayParamName);
final Integer recurrenceOnDay = command.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyOnDayParamName);
final Integer recurrenceOnWeekday = command
.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyWeekdayParamName);
Integer recurrenceInterval = command
.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyIntervalParameterName);
final boolean isArrearsBasedOnOriginalSchedule = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.isArrearsBasedOnOriginalScheduleParamName);
RecalculationFrequencyType frequencyType = RecalculationFrequencyType.fromInt(recurrenceFrequency);
if (frequencyType.isSameAsRepayment()) {
recurrenceInterval = 0;
}
InterestRecalculationCompoundingMethod compoundingMethod = InterestRecalculationCompoundingMethod
.fromInt(interestRecalculationCompoundingMethod);
Integer compoundingRecurrenceFrequency = null;
Integer compoundingInterval = null;
Integer compoundingRecurrenceOnNthDay = null;
Integer compoundingRecurrenceOnDay = null;
Integer compoundingRecurrenceOnWeekday = null;
boolean allowCompoundingOnEod = false;
if (compoundingMethod.isCompoundingEnabled()) {
compoundingRecurrenceFrequency = command
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyTypeParameterName);
compoundingInterval = command
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyIntervalParameterName);
RecalculationFrequencyType compoundingFrequencyType = RecalculationFrequencyType.fromInt(compoundingRecurrenceFrequency);
if (compoundingFrequencyType.isSameAsRepayment()) {
recurrenceInterval = 0;
}
compoundingRecurrenceOnNthDay = command
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyNthDayParamName);
compoundingRecurrenceOnDay = command
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyOnDayParamName);
compoundingRecurrenceOnWeekday = command
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyWeekdayParamName);
if (!compoundingFrequencyType.isDaily()) {
allowCompoundingOnEod = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.allowCompoundingOnEodParamName);
}
}
Integer preCloseInterestCalculationStrategy = command
.integerValueOfParameterNamed(LoanProductConstants.preClosureInterestCalculationStrategyParamName);
if (preCloseInterestCalculationStrategy == null) {
preCloseInterestCalculationStrategy = LoanPreCloseInterestCalculationStrategy.TILL_PRE_CLOSURE_DATE.getValue();
}
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, disallowInterestCalculationOnPastDue);
}
private LoanProductInterestRecalculationDetails(final Integer interestRecalculationCompoundingMethod,
public LoanProductInterestRecalculationDetails(final Integer interestRecalculationCompoundingMethod,
final Integer rescheduleStrategyMethod, final Integer restFrequencyType, final Integer restInterval,
final Integer restFrequencyNthDay, final Integer restFrequencyOnDay, final Integer restFrequencyWeekday,
Integer compoundingFrequencyType, Integer compoundingInterval, final Integer compoundingFrequencyNthDay,
@@ -206,280 +135,15 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
this.loanProduct = loanProduct;
}
public Integer getInterestRecalculationCompoundingMethod() {
return this.interestRecalculationCompoundingMethod;
}
public Integer getRescheduleStrategyMethod() {
return this.rescheduleStrategyMethod;
}
public void update(final JsonCommand command, final Map<String, Object> actualChanges, final String localeAsInput) {
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.interestRecalculationCompoundingMethodParameterName,
this.interestRecalculationCompoundingMethod)) {
final Integer newValue = command
.integerValueOfParameterNamed(LoanProductConstants.interestRecalculationCompoundingMethodParameterName);
actualChanges.put(LoanProductConstants.interestRecalculationCompoundingMethodParameterName, newValue);
actualChanges.put("locale", localeAsInput);
this.interestRecalculationCompoundingMethod = InterestRecalculationCompoundingMethod.fromInt(newValue).getValue();
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.rescheduleStrategyMethodParameterName,
this.rescheduleStrategyMethod)) {
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.rescheduleStrategyMethodParameterName);
actualChanges.put(LoanProductConstants.rescheduleStrategyMethodParameterName, newValue);
actualChanges.put("locale", localeAsInput);
this.rescheduleStrategyMethod = LoanRescheduleStrategyMethod.fromInt(newValue).getValue();
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationRestFrequencyTypeParameterName,
this.restFrequencyType)) {
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyTypeParameterName);
actualChanges.put(LoanProductConstants.recalculationRestFrequencyTypeParameterName, newValue);
actualChanges.put("locale", localeAsInput);
this.restFrequencyType = RecalculationFrequencyType.fromInt(newValue).getValue();
}
RecalculationFrequencyType frequencyType = RecalculationFrequencyType.fromInt(this.restFrequencyType);
if (frequencyType.isSameAsRepayment()) {
this.restInterval = 0;
this.restFrequencyNthDay = null;
this.restFrequencyWeekday = null;
this.restFrequencyOnDay = null;
} else {
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationRestFrequencyIntervalParameterName,
this.restInterval)) {
Integer newValue = command
.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyIntervalParameterName);
actualChanges.put(LoanProductConstants.recalculationRestFrequencyIntervalParameterName, newValue);
actualChanges.put("locale", localeAsInput);
this.restInterval = newValue;
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationRestFrequencyNthDayParamName,
getRestFrequencyNthDay())) {
Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyNthDayParamName);
actualChanges.put(LoanProductConstants.recalculationRestFrequencyNthDayParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.restFrequencyNthDay = newValue;
this.restFrequencyOnDay = null;
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationRestFrequencyWeekdayParamName,
getRestFrequencyWeekday())) {
Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyWeekdayParamName);
actualChanges.put(LoanProductConstants.recalculationRestFrequencyWeekdayParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.restFrequencyWeekday = newValue;
this.restFrequencyOnDay = null;
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationRestFrequencyOnDayParamName,
getRestFrequencyOnDay())) {
Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyOnDayParamName);
actualChanges.put(LoanProductConstants.recalculationRestFrequencyOnDayParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.restFrequencyOnDay = newValue;
this.restFrequencyNthDay = null;
this.restFrequencyWeekday = null;
}
if (frequencyType.isWeekly()) {
this.restFrequencyNthDay = null;
this.restFrequencyOnDay = null;
} else if (frequencyType.isMonthly()) {
if (command.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyOnDayParamName) != null) {
this.restFrequencyNthDay = null;
this.restFrequencyWeekday = null;
} else {
this.restFrequencyOnDay = null;
}
} else if (frequencyType.isDaily()) {
this.restFrequencyNthDay = null;
this.restFrequencyWeekday = null;
this.restFrequencyOnDay = null;
}
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyTypeParameterName,
this.compoundingFrequencyType)) {
final Integer newValue = command
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyTypeParameterName);
actualChanges.put(LoanProductConstants.recalculationCompoundingFrequencyTypeParameterName, newValue);
this.compoundingFrequencyType = RecalculationFrequencyType.fromInt(newValue).getValue();
}
InterestRecalculationCompoundingMethod compoundingMethod = InterestRecalculationCompoundingMethod
.fromInt(this.interestRecalculationCompoundingMethod);
if (compoundingMethod.isCompoundingEnabled()) {
RecalculationFrequencyType compoundingFrequencyType = RecalculationFrequencyType.fromInt(this.compoundingFrequencyType);
if (compoundingFrequencyType.isSameAsRepayment()) {
this.compoundingInterval = null;
this.compoundingFrequencyNthDay = null;
this.compoundingFrequencyWeekday = null;
this.compoundingFrequencyOnDay = null;
} else {
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyIntervalParameterName,
this.compoundingInterval)) {
Integer newValue = command
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyIntervalParameterName);
actualChanges.put(LoanProductConstants.recalculationCompoundingFrequencyIntervalParameterName, newValue);
this.compoundingInterval = newValue;
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyNthDayParamName,
getCompoundingFrequencyNthDay())) {
Integer newValue = command
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyNthDayParamName);
actualChanges.put(LoanProductConstants.recalculationCompoundingFrequencyNthDayParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.compoundingFrequencyNthDay = newValue;
this.compoundingFrequencyOnDay = null;
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyWeekdayParamName,
getCompoundingFrequencyWeekday())) {
Integer newValue = command
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyWeekdayParamName);
actualChanges.put(LoanProductConstants.recalculationCompoundingFrequencyWeekdayParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.compoundingFrequencyWeekday = newValue;
this.compoundingFrequencyOnDay = null;
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyOnDayParamName,
getCompoundingFrequencyOnDay())) {
Integer newValue = command
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyOnDayParamName);
actualChanges.put(LoanProductConstants.recalculationCompoundingFrequencyOnDayParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.compoundingFrequencyOnDay = newValue;
this.compoundingFrequencyNthDay = null;
this.compoundingFrequencyWeekday = null;
}
if (compoundingFrequencyType.isWeekly()) {
this.compoundingFrequencyNthDay = null;
this.compoundingFrequencyOnDay = null;
} else if (compoundingFrequencyType.isMonthly()) {
if (command
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyOnDayParamName) != null) {
this.compoundingFrequencyNthDay = null;
this.compoundingFrequencyWeekday = null;
} else {
this.compoundingFrequencyOnDay = null;
}
} else if (compoundingFrequencyType.isDaily()) {
this.compoundingFrequencyNthDay = null;
this.compoundingFrequencyWeekday = null;
this.compoundingFrequencyOnDay = null;
}
}
if (!compoundingFrequencyType.isDaily()) {
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.allowCompoundingOnEodParamName, allowCompoundingOnEod())) {
boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.allowCompoundingOnEodParamName);
actualChanges.put(LoanProductConstants.allowCompoundingOnEodParamName, newValue);
this.allowCompoundingOnEod = newValue;
}
} else {
this.allowCompoundingOnEod = false;
}
} else {
this.compoundingFrequencyType = null;
this.compoundingInterval = null;
this.compoundingFrequencyNthDay = null;
this.compoundingFrequencyWeekday = null;
this.compoundingFrequencyOnDay = null;
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.isArrearsBasedOnOriginalScheduleParamName,
this.isArrearsBasedOnOriginalSchedule)) {
final boolean newValue = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.isArrearsBasedOnOriginalScheduleParamName);
actualChanges.put(LoanProductConstants.isArrearsBasedOnOriginalScheduleParamName, newValue);
this.isArrearsBasedOnOriginalSchedule = newValue;
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.preClosureInterestCalculationStrategyParamName,
this.preCloseInterestCalculationStrategy)) {
Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.preClosureInterestCalculationStrategyParamName);
if (newValue == null) {
newValue = LoanPreCloseInterestCalculationStrategy.TILL_PRE_CLOSURE_DATE.getValue();
}
actualChanges.put(LoanProductConstants.preClosureInterestCalculationStrategyParamName, newValue);
this.preCloseInterestCalculationStrategy = newValue;
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.isCompoundingToBePostedAsTransactionParamName,
this.isCompoundingToBePostedAsTransaction)) {
final boolean newValue = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.isCompoundingToBePostedAsTransactionParamName);
actualChanges.put(LoanProductConstants.isCompoundingToBePostedAsTransactionParamName, newValue);
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() {
return RecalculationFrequencyType.fromInt(this.restFrequencyType);
}
public Integer getRestInterval() {
return this.restInterval;
}
public RecalculationFrequencyType getCompoundingFrequencyType() {
return RecalculationFrequencyType.fromInt(this.compoundingFrequencyType);
}
public Integer getCompoundingInterval() {
return this.compoundingInterval;
}
public boolean isArrearsBasedOnOriginalSchedule() {
return this.isArrearsBasedOnOriginalSchedule;
}
public LoanPreCloseInterestCalculationStrategy getPreCloseInterestCalculationStrategy() {
return LoanPreCloseInterestCalculationStrategy.fromInt(this.preCloseInterestCalculationStrategy);
}
public Integer getRestFrequencyNthDay() {
return this.restFrequencyNthDay;
}
public Integer getRestFrequencyWeekday() {
return this.restFrequencyWeekday;
}
public Integer getRestFrequencyOnDay() {
return this.restFrequencyOnDay;
}
public Integer getCompoundingFrequencyNthDay() {
return this.compoundingFrequencyNthDay;
}
public Integer getCompoundingFrequencyWeekday() {
return this.compoundingFrequencyWeekday;
}
public Integer getCompoundingFrequencyOnDay() {
return this.compoundingFrequencyOnDay;
}
public Boolean getIsCompoundingToBePostedAsTransaction() {
return this.isCompoundingToBePostedAsTransaction;
}
public Boolean allowCompoundingOnEod() {
return this.allowCompoundingOnEod;
}
public Boolean disallowInterestCalculationOnPastDue() {
return disallowInterestCalculationOnPastDue;
}
}
@@ -25,12 +25,9 @@ import jakarta.persistence.Embedded;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import lombok.Getter;
import lombok.Setter;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
@@ -40,10 +37,8 @@ import org.apache.fineract.portfolio.common.domain.DaysInYearType;
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeOffBehaviour;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.AprCalculator;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
/**
* LoanRepaymentScheduleDetail encapsulates all the details of a {@link LoanProduct} that are also used and persisted by
@@ -308,259 +303,6 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
return daysInYearCustomStrategy;
}
// TODO: Move into assembler
public Map<String, Object> update(final JsonCommand command, final AprCalculator aprCalculator) {
final Map<String, Object> actualChanges = new LinkedHashMap<>(20);
final String localeAsInput = command.locale();
String currencyCode = this.currency.getCode();
Integer digitsAfterDecimal = this.currency.getDigitsAfterDecimal();
Integer inMultiplesOf = this.currency.getCurrencyInMultiplesOf();
final String digitsAfterDecimalParamName = "digitsAfterDecimal";
if (command.isChangeInIntegerParameterNamed(digitsAfterDecimalParamName, digitsAfterDecimal)) {
final Integer newValue = command.integerValueOfParameterNamed(digitsAfterDecimalParamName);
actualChanges.put(digitsAfterDecimalParamName, newValue);
actualChanges.put("locale", localeAsInput);
digitsAfterDecimal = newValue;
this.currency = new MonetaryCurrency(currencyCode, digitsAfterDecimal, inMultiplesOf);
}
final String currencyCodeParamName = "currencyCode";
if (command.isChangeInStringParameterNamed(currencyCodeParamName, currencyCode)) {
final String newValue = command.stringValueOfParameterNamed(currencyCodeParamName);
actualChanges.put(currencyCodeParamName, newValue);
currencyCode = newValue;
this.currency = new MonetaryCurrency(currencyCode, digitsAfterDecimal, inMultiplesOf);
}
final String inMultiplesOfParamName = "inMultiplesOf";
if (command.isChangeInStringParameterNamed(inMultiplesOfParamName, currencyCode)) {
final Integer newValue = command.integerValueOfParameterNamed(inMultiplesOfParamName);
actualChanges.put(inMultiplesOfParamName, newValue);
inMultiplesOf = newValue;
this.currency = new MonetaryCurrency(currencyCode, digitsAfterDecimal, inMultiplesOf);
}
final String loanScheduleTypeParamName = LoanProductConstants.LOAN_SCHEDULE_TYPE;
if (command.isChangeInStringParameterNamed(loanScheduleTypeParamName, loanScheduleType.toString())) {
LoanScheduleType newLoanScheduleType = LoanScheduleType.valueOf(command.stringValueOfParameterNamed(loanScheduleTypeParamName));
actualChanges.put(loanScheduleTypeParamName, newLoanScheduleType);
loanScheduleType = newLoanScheduleType;
}
final String loanScheduleProcessingTypeParamName = LoanProductConstants.LOAN_SCHEDULE_PROCESSING_TYPE;
if (command.isChangeInStringParameterNamed(loanScheduleProcessingTypeParamName, loanScheduleProcessingType.toString())) {
LoanScheduleProcessingType newLoanScheduleProcessingType = LoanScheduleProcessingType
.valueOf(command.stringValueOfParameterNamed(loanScheduleProcessingTypeParamName));
actualChanges.put(loanScheduleProcessingTypeParamName, newLoanScheduleProcessingType);
loanScheduleProcessingType = newLoanScheduleProcessingType;
}
final String principalParamName = "principal";
if (command.isChangeInBigDecimalParameterNamed(principalParamName, this.principal)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(principalParamName);
actualChanges.put(principalParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.principal = newValue;
}
final String repaymentEveryParamName = "repaymentEvery";
if (command.isChangeInIntegerParameterNamed(repaymentEveryParamName, this.repayEvery)) {
final Integer newValue = command.integerValueOfParameterNamed(repaymentEveryParamName);
actualChanges.put(repaymentEveryParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.repayEvery = newValue;
}
final String repaymentFrequencyTypeParamName = "repaymentFrequencyType";
if (command.isChangeInIntegerParameterNamed(repaymentFrequencyTypeParamName, this.repaymentPeriodFrequencyType.getValue())) {
Integer newValue = command.integerValueOfParameterNamed(repaymentFrequencyTypeParamName);
actualChanges.put(repaymentFrequencyTypeParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.repaymentPeriodFrequencyType = PeriodFrequencyType.fromInt(newValue);
}
if (this.repaymentPeriodFrequencyType == PeriodFrequencyType.MONTHS) {
Integer newValue = null;
final String repaymentFrequencyNthDayTypeParamName = "repaymentFrequencyNthDayType";
newValue = command.integerValueOfParameterNamed(repaymentFrequencyNthDayTypeParamName);
actualChanges.put(repaymentFrequencyNthDayTypeParamName, newValue);
final String repaymentFrequencyDayOfWeekTypeParamName = "repaymentFrequencyDayOfWeekType";
newValue = command.integerValueOfParameterNamed(repaymentFrequencyDayOfWeekTypeParamName);
actualChanges.put(repaymentFrequencyDayOfWeekTypeParamName, newValue);
actualChanges.put("locale", localeAsInput);
}
final String numberOfRepaymentsParamName = "numberOfRepayments";
if (command.isChangeInIntegerParameterNamed(numberOfRepaymentsParamName, this.numberOfRepayments)) {
final Integer newValue = command.integerValueOfParameterNamed(numberOfRepaymentsParamName);
actualChanges.put(numberOfRepaymentsParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.numberOfRepayments = newValue;
}
final String amortizationTypeParamName = "amortizationType";
if (command.isChangeInIntegerParameterNamed(amortizationTypeParamName, this.amortizationMethod.getValue())) {
final Integer newValue = command.integerValueOfParameterNamed(amortizationTypeParamName);
actualChanges.put(amortizationTypeParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.amortizationMethod = AmortizationMethod.fromInt(newValue);
}
final String inArrearsToleranceParamName = "inArrearsTolerance";
if (command.isChangeInBigDecimalParameterNamed(inArrearsToleranceParamName, this.inArrearsTolerance)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(inArrearsToleranceParamName);
actualChanges.put(inArrearsToleranceParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.inArrearsTolerance = newValue;
}
final String interestRatePerPeriodParamName = "interestRatePerPeriod";
if (command.isChangeInBigDecimalParameterNamed(interestRatePerPeriodParamName, this.nominalInterestRatePerPeriod)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(interestRatePerPeriodParamName);
actualChanges.put(interestRatePerPeriodParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.nominalInterestRatePerPeriod = newValue;
updateInterestRateDerivedFields(aprCalculator);
}
final String interestRateFrequencyTypeParamName = "interestRateFrequencyType";
final int interestPeriodFrequencyType = this.interestPeriodFrequencyType == null ? PeriodFrequencyType.INVALID.getValue()
: this.interestPeriodFrequencyType.getValue();
if (command.isChangeInIntegerParameterNamed(interestRateFrequencyTypeParamName, interestPeriodFrequencyType)) {
final Integer newValue = command.integerValueOfParameterNamed(interestRateFrequencyTypeParamName);
actualChanges.put(interestRateFrequencyTypeParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.interestPeriodFrequencyType = PeriodFrequencyType.fromInt(newValue);
updateInterestRateDerivedFields(aprCalculator);
}
final String interestTypeParamName = "interestType";
if (command.isChangeInIntegerParameterNamed(interestTypeParamName, this.interestMethod.getValue())) {
final Integer newValue = command.integerValueOfParameterNamed(interestTypeParamName);
actualChanges.put(interestTypeParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.interestMethod = InterestMethod.fromInt(newValue);
}
final String interestCalculationPeriodTypeParamName = "interestCalculationPeriodType";
if (command.isChangeInIntegerParameterNamed(interestCalculationPeriodTypeParamName,
this.interestCalculationPeriodMethod.getValue())) {
final Integer newValue = command.integerValueOfParameterNamed(interestCalculationPeriodTypeParamName);
actualChanges.put(interestCalculationPeriodTypeParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(newValue);
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.ALLOW_PARTIAL_PERIOD_INTEREST_CALCUALTION_PARAM_NAME,
this.allowPartialPeriodInterestCalcualtion)) {
final boolean newValue = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ALLOW_PARTIAL_PERIOD_INTEREST_CALCUALTION_PARAM_NAME);
actualChanges.put(LoanProductConstants.ALLOW_PARTIAL_PERIOD_INTEREST_CALCUALTION_PARAM_NAME, newValue);
this.allowPartialPeriodInterestCalcualtion = newValue;
}
if (this.interestCalculationPeriodMethod.isDaily()) {
this.allowPartialPeriodInterestCalcualtion = false;
}
final String graceOnPrincipalPaymentParamName = "graceOnPrincipalPayment";
if (command.isChangeInIntegerParameterNamed(graceOnPrincipalPaymentParamName, this.graceOnPrincipalPayment)) {
final Integer newValue = command.integerValueOfParameterNamed(graceOnPrincipalPaymentParamName);
actualChanges.put(graceOnPrincipalPaymentParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.graceOnPrincipalPayment = newValue;
}
final String recurringMoratoriumOnPrincipalPeriodsParamName = "recurringMoratoriumOnPrincipalPeriods";
if (command.isChangeInIntegerParameterNamed(recurringMoratoriumOnPrincipalPeriodsParamName,
this.recurringMoratoriumOnPrincipalPeriods)) {
final Integer newValue = command.integerValueOfParameterNamed(recurringMoratoriumOnPrincipalPeriodsParamName);
actualChanges.put(recurringMoratoriumOnPrincipalPeriodsParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.recurringMoratoriumOnPrincipalPeriods = newValue;
}
final String graceOnInterestPaymentParamName = "graceOnInterestPayment";
if (command.isChangeInIntegerParameterNamed(graceOnInterestPaymentParamName, this.graceOnInterestPayment)) {
final Integer newValue = command.integerValueOfParameterNamed(graceOnInterestPaymentParamName);
actualChanges.put(graceOnInterestPaymentParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.graceOnInterestPayment = newValue;
}
final String graceOnInterestChargedParamName = "graceOnInterestCharged";
if (command.isChangeInIntegerParameterNamed(graceOnInterestChargedParamName, this.graceOnInterestCharged)) {
final Integer newValue = command.integerValueOfParameterNamed(graceOnInterestChargedParamName);
actualChanges.put(graceOnInterestChargedParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.graceOnInterestCharged = newValue;
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.GRACE_ON_ARREARS_AGEING_PARAMETER_NAME,
this.graceOnArrearsAgeing)) {
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.GRACE_ON_ARREARS_AGEING_PARAMETER_NAME);
actualChanges.put(LoanProductConstants.GRACE_ON_ARREARS_AGEING_PARAMETER_NAME, newValue);
actualChanges.put("locale", localeAsInput);
this.graceOnArrearsAgeing = newValue;
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.DAYS_IN_MONTH_TYPE_PARAMETER_NAME, this.daysInMonthType)) {
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.DAYS_IN_MONTH_TYPE_PARAMETER_NAME);
actualChanges.put(LoanProductConstants.DAYS_IN_MONTH_TYPE_PARAMETER_NAME, newValue);
actualChanges.put("locale", localeAsInput);
this.daysInMonthType = newValue;
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.DAYS_IN_YEAR_TYPE_PARAMETER_NAME, this.daysInYearType)) {
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.DAYS_IN_YEAR_TYPE_PARAMETER_NAME);
actualChanges.put(LoanProductConstants.DAYS_IN_YEAR_TYPE_PARAMETER_NAME, newValue);
actualChanges.put("locale", localeAsInput);
this.daysInYearType = newValue;
}
if (command.parameterExists(LoanProductConstants.DAYS_IN_YEAR_CUSTOM_STRATEGY_TYPE_PARAMETER_NAME)) {
final DaysInYearCustomStrategyType newValue = DaysInYearCustomStrategyType
.valueOf(command.stringValueOfParameterNamed(LoanProductConstants.DAYS_IN_YEAR_CUSTOM_STRATEGY_TYPE_PARAMETER_NAME));
actualChanges.put(LoanProductConstants.DAYS_IN_YEAR_CUSTOM_STRATEGY_TYPE_PARAMETER_NAME, newValue.name());
this.daysInYearCustomStrategy = newValue;
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.IS_INTEREST_RECALCULATION_ENABLED_PARAMETER_NAME,
this.isInterestRecalculationEnabled)) {
final boolean newValue = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.IS_INTEREST_RECALCULATION_ENABLED_PARAMETER_NAME);
actualChanges.put(LoanProductConstants.IS_INTEREST_RECALCULATION_ENABLED_PARAMETER_NAME, newValue);
this.isInterestRecalculationEnabled = newValue;
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM, this.isEqualAmortization)) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM);
actualChanges.put(LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM, newValue);
this.isEqualAmortization = newValue;
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE,
this.isInterestRecognitionOnDisbursementDate())) {
final boolean newValue = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE);
actualChanges.put(LoanProductConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE, newValue);
this.updateInterestRecognitionOnDisbursementDate(newValue);
}
return actualChanges;
}
public void updateInterestRateDerivedFields(final AprCalculator aprCalculator) {
this.annualNominalInterestRate = aprCalculator.calculateFrom(this.interestPeriodFrequencyType, this.nominalInterestRatePerPeriod,
this.numberOfRepayments, this.repayEvery, this.repaymentPeriodFrequencyType);
}
public boolean hasCurrencyCodeOf(final String currencyCode) {
return this.currency.getCode().equalsIgnoreCase(currencyCode);
}
@@ -21,10 +21,11 @@ package org.apache.fineract.portfolio.loanproduct.domain;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import java.math.BigDecimal;
import java.util.Map;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Embeddable
public class LoanProductTrancheDetails {
@@ -48,43 +49,4 @@ public class LoanProductTrancheDetails {
this.outstandingLoanBalance = outstandingLoanBalance;
}
public void update(final JsonCommand command, final Map<String, Object> actualChanges, final String localeAsInput) {
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.MULTI_DISBURSE_LOAN_PARAMETER_NAME, this.multiDisburseLoan)) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.MULTI_DISBURSE_LOAN_PARAMETER_NAME);
actualChanges.put(LoanProductConstants.MULTI_DISBURSE_LOAN_PARAMETER_NAME, newValue);
this.multiDisburseLoan = newValue;
}
if (this.multiDisburseLoan) {
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.MAX_TRANCHE_COUNT_PARAMETER_NAME, this.maxTrancheCount)) {
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.MAX_TRANCHE_COUNT_PARAMETER_NAME);
actualChanges.put(LoanProductConstants.MAX_TRANCHE_COUNT_PARAMETER_NAME, newValue);
this.maxTrancheCount = newValue;
}
if (command.isChangeInBigDecimalParameterNamed(LoanProductConstants.OUTSTANDING_LOAN_BALANCE_PARAMETER_NAME,
this.outstandingLoanBalance)) {
final BigDecimal newValue = command
.bigDecimalValueOfParameterNamed(LoanProductConstants.OUTSTANDING_LOAN_BALANCE_PARAMETER_NAME);
actualChanges.put(LoanProductConstants.OUTSTANDING_LOAN_BALANCE_PARAMETER_NAME, newValue);
this.outstandingLoanBalance = newValue;
}
} else {
this.maxTrancheCount = null;
this.outstandingLoanBalance = null;
}
}
public boolean isMultiDisburseLoan() {
return this.multiDisburseLoan;
}
public BigDecimal outstandingLoanBalance() {
return this.outstandingLoanBalance;
}
public Integer maxTrancheCount() {
return this.maxTrancheCount;
}
}
@@ -23,18 +23,15 @@ import jakarta.persistence.Entity;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToOne;
import jakarta.persistence.Table;
import java.util.LinkedHashMap;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "m_product_loan_variable_installment_config")
@@ -50,22 +47,4 @@ public class LoanProductVariableInstallmentConfig extends AbstractPersistableCus
@Column(name = "maximum_gap")
private Integer maximumGap;
public Map<? extends String, ?> update(JsonCommand command) {
final Map<String, Object> actualChanges = new LinkedHashMap<>(3);
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.minimumGapBetweenInstallments, this.minimumGap)) {
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.minimumGapBetweenInstallments);
actualChanges.put(LoanProductConstants.minimumGapBetweenInstallments, newValue);
this.minimumGap = newValue;
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.maximumGapBetweenInstallments, this.maximumGap)) {
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.maximumGapBetweenInstallments);
actualChanges.put(LoanProductConstants.maximumGapBetweenInstallments, newValue);
this.maximumGap = newValue;
}
return actualChanges;
}
}