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;
}
}
@@ -118,6 +118,7 @@ import org.apache.fineract.portfolio.loanaccount.service.LoanChargeAssembler;
import org.apache.fineract.portfolio.loanaccount.service.LoanChargeService;
import org.apache.fineract.portfolio.loanaccount.service.LoanDisbursementDetailsAssembler;
import org.apache.fineract.portfolio.loanaccount.service.LoanDisbursementService;
import org.apache.fineract.portfolio.loanaccount.service.LoanProductRelatedDetailUpdateUtil;
import org.apache.fineract.portfolio.loanaccount.service.LoanScheduleService;
import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
@@ -164,6 +165,7 @@ public class LoanScheduleAssembler {
private final LoanDisbursementService loanDisbursementService;
private final LoanChargeService loanChargeService;
private final LoanScheduleService loanScheduleService;
private final LoanProductRelatedDetailUpdateUtil relatedDetailUpdateUtil;
public LoanApplicationTerms assembleLoanTerms(final JsonElement element) {
final Long loanProductId = this.fromApiJsonHelper.extractLongNamed("productId", element);
@@ -421,7 +423,7 @@ public class LoanScheduleAssembler {
loanProductInterestRecalculationDetails.getCompoundingInterval(), recalculationCompoundingFrequencyNthDay,
compoundingRepeatsOnDay);
}
allowCompoundingOnEod = loanProductInterestRecalculationDetails.allowCompoundingOnEod();
allowCompoundingOnEod = loanProductInterestRecalculationDetails.getAllowCompoundingOnEod();
}
}
@@ -1303,7 +1305,7 @@ public class LoanScheduleAssembler {
changes.put(interestRatePerPeriodParamName, newValue);
changes.put("locale", localeAsInput);
loanProductRelatedDetail.setNominalInterestRatePerPeriod(newValue);
loanProductRelatedDetail.updateInterestRateDerivedFields(aprCalculator);
relatedDetailUpdateUtil.updateInterestRateDerivedFields(loanProductRelatedDetail, aprCalculator);
}
final String interestRateFrequencyTypeParamName = "interestRateFrequencyType";
@@ -1315,7 +1317,7 @@ public class LoanScheduleAssembler {
changes.put(interestRateFrequencyTypeParamName, newValue);
changes.put("locale", localeAsInput);
loanProductRelatedDetail.setInterestPeriodFrequencyType(PeriodFrequencyType.fromInt(newValue));
loanProductRelatedDetail.updateInterestRateDerivedFields(aprCalculator);
relatedDetailUpdateUtil.updateInterestRateDerivedFields(loanProductRelatedDetail, aprCalculator);
}
final String interestTypeParamName = "interestType";
@@ -0,0 +1,406 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.loanaccount.service;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import lombok.RequiredArgsConstructor;
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.ExternalId;
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.portfolio.charge.domain.Charge;
import org.apache.fineract.portfolio.common.domain.DaysInMonthType;
import org.apache.fineract.portfolio.common.domain.DaysInYearCustomStrategyType;
import org.apache.fineract.portfolio.common.domain.DaysInYearType;
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
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;
import org.apache.fineract.portfolio.loanproduct.domain.AmortizationMethod;
import org.apache.fineract.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductBorrowerCycleVariations;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductConfigurableAttributes;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductCreditAllocationRule;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductGuaranteeDetails;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductInterestRecalculationDetails;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductParamType;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductPaymentAllocationRule;
import org.apache.fineract.portfolio.loanproduct.domain.LoanSupportedInterestRefundTypes;
import org.apache.fineract.portfolio.loanproduct.domain.RepaymentStartDateType;
import org.apache.fineract.portfolio.rate.domain.Rate;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class LoanProductAssembler {
private final LoanProductInterestRecalculationDetailsAssembler interestRecalculationDetailsAssembler;
private final LoanProductGuaranteeDetailsAssembler guaranteeDetailsAssembler;
public 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 = interestRecalculationDetailsAssembler.createFrom(command);
}
final boolean holdGuarantorFunds = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.holdGuaranteeFundsParamName);
LoanProductGuaranteeDetails loanProductGuaranteeDetails = null;
if (holdGuarantorFunds) {
loanProductGuaranteeDetails = guaranteeDetailsAssembler.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);
}
private void populateBorrowerCycleVariations(final JsonCommand command,
final Set<LoanProductBorrowerCycleVariations> loanProductBorrowerCycleVariations) {
assemblePrincipalVariations(command, loanProductBorrowerCycleVariations);
assembleRepaymentVariations(command, loanProductBorrowerCycleVariations);
assembleInterestRateVariations(command, loanProductBorrowerCycleVariations);
}
private 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 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 void assemblePrincipalVariations(final JsonCommand command,
final Set<LoanProductBorrowerCycleVariations> loanProductBorrowerCycleVariations) {
assembleVariations(command, loanProductBorrowerCycleVariations, LoanProductParamType.PRINCIPAL.getValue(),
LoanProductConstants.PRINCIPAL_VARIATIONS_FOR_BORROWER_CYCLE_PARAMETER_NAME);
}
private 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());
}
}
}
}
@@ -0,0 +1,84 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.loanaccount.service;
import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.portfolio.floatingrates.domain.FloatingRate;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductFloatingRates;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class LoanProductFloatingRatesUpdateUtil {
public Map<? extends String, ?> update(LoanProductFloatingRates loanProductFloatingRates, JsonCommand command,
FloatingRate floatingRate) {
final Map<String, Object> actualChanges = new LinkedHashMap<>(20);
if (floatingRate != null) {
final String floatingRatesId = "floatingRatesId";
if (loanProductFloatingRates.getFloatingRate() == null
|| command.isChangeInLongParameterNamed(floatingRatesId, loanProductFloatingRates.getFloatingRate().getId())) {
final long newValue = command.longValueOfParameterNamed(floatingRatesId);
actualChanges.put(floatingRatesId, newValue);
loanProductFloatingRates.setFloatingRate(floatingRate);
}
}
final String interestRateDifferential = "interestRateDifferential";
if (command.isChangeInBigDecimalParameterNamed(interestRateDifferential, loanProductFloatingRates.getInterestRateDifferential())) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(interestRateDifferential);
actualChanges.put(interestRateDifferential, newValue);
loanProductFloatingRates.setInterestRateDifferential(newValue);
}
final String minDifferentialLendingRate = "minDifferentialLendingRate";
if (command.isChangeInBigDecimalParameterNamed(minDifferentialLendingRate,
loanProductFloatingRates.getMinDifferentialLendingRate())) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(minDifferentialLendingRate);
actualChanges.put(minDifferentialLendingRate, newValue);
loanProductFloatingRates.setMinDifferentialLendingRate(newValue);
}
final String defaultDifferentialLendingRate = "defaultDifferentialLendingRate";
if (command.isChangeInBigDecimalParameterNamed(defaultDifferentialLendingRate,
loanProductFloatingRates.getDefaultDifferentialLendingRate())) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(defaultDifferentialLendingRate);
actualChanges.put(defaultDifferentialLendingRate, newValue);
loanProductFloatingRates.setDefaultDifferentialLendingRate(newValue);
}
final String maxDifferentialLendingRate = "maxDifferentialLendingRate";
if (command.isChangeInBigDecimalParameterNamed(maxDifferentialLendingRate,
loanProductFloatingRates.getMaxDifferentialLendingRate())) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(maxDifferentialLendingRate);
actualChanges.put(maxDifferentialLendingRate, newValue);
loanProductFloatingRates.setMaxDifferentialLendingRate(newValue);
}
final String isFloatingInterestRateCalculationAllowed = "isFloatingInterestRateCalculationAllowed";
if (command.isChangeInBooleanParameterNamed(isFloatingInterestRateCalculationAllowed,
loanProductFloatingRates.isFloatingInterestRateCalculationAllowed())) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(isFloatingInterestRateCalculationAllowed);
actualChanges.put(isFloatingInterestRateCalculationAllowed, newValue);
loanProductFloatingRates.setFloatingInterestRateCalculationAllowed(newValue);
}
return actualChanges;
}
}
@@ -0,0 +1,42 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.loanaccount.service;
import java.math.BigDecimal;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductGuaranteeDetails;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class LoanProductGuaranteeDetailsAssembler {
public 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);
}
}
@@ -0,0 +1,59 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.loanaccount.service;
import java.math.BigDecimal;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductGuaranteeDetails;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class LoanProductGuaranteeDetailsUpdateUtil {
public void update(final LoanProductGuaranteeDetails loanProductGuaranteeDetails, final JsonCommand command,
final Map<String, Object> actualChanges) {
if (command.isChangeInBigDecimalParameterNamed(LoanProductConstants.mandatoryGuaranteeParamName,
loanProductGuaranteeDetails.getMandatoryGuarantee())) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(LoanProductConstants.mandatoryGuaranteeParamName);
actualChanges.put(LoanProductConstants.mandatoryGuaranteeParamName, newValue);
loanProductGuaranteeDetails.setMandatoryGuarantee(newValue);
}
if (command.isChangeInBigDecimalParameterNamed(LoanProductConstants.minimumGuaranteeFromGuarantorParamName,
loanProductGuaranteeDetails.getMinimumGuaranteeFromGuarantor())) {
final BigDecimal newValue = command
.bigDecimalValueOfParameterNamed(LoanProductConstants.minimumGuaranteeFromGuarantorParamName);
actualChanges.put(LoanProductConstants.minimumGuaranteeFromGuarantorParamName, newValue);
loanProductGuaranteeDetails.setMinimumGuaranteeFromGuarantor(newValue);
}
if (command.isChangeInBigDecimalParameterNamed(LoanProductConstants.minimumGuaranteeFromOwnFundsParamName,
loanProductGuaranteeDetails.getMinimumGuaranteeFromOwnFunds())) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(LoanProductConstants.minimumGuaranteeFromOwnFundsParamName);
actualChanges.put(LoanProductConstants.minimumGuaranteeFromOwnFundsParamName, newValue);
loanProductGuaranteeDetails.setMinimumGuaranteeFromOwnFunds(newValue);
}
}
}
@@ -0,0 +1,105 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.loanaccount.service;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
import org.apache.fineract.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod;
import org.apache.fineract.portfolio.loanproduct.domain.LoanPreCloseInterestCalculationStrategy;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductInterestRecalculationDetails;
import org.apache.fineract.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod;
import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class LoanProductInterestRecalculationDetailsAssembler {
public 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);
}
}
@@ -0,0 +1,247 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.loanaccount.service;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
import org.apache.fineract.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod;
import org.apache.fineract.portfolio.loanproduct.domain.LoanPreCloseInterestCalculationStrategy;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductInterestRecalculationDetails;
import org.apache.fineract.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod;
import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class LoanProductInterestRecalculationDetailsUpdateUtil {
public void update(final LoanProductInterestRecalculationDetails loanProductInterestRecalculationDetails, final JsonCommand command,
final Map<String, Object> actualChanges, final String localeAsInput) {
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.interestRecalculationCompoundingMethodParameterName,
loanProductInterestRecalculationDetails.getInterestRecalculationCompoundingMethod())) {
final Integer newValue = command
.integerValueOfParameterNamed(LoanProductConstants.interestRecalculationCompoundingMethodParameterName);
actualChanges.put(LoanProductConstants.interestRecalculationCompoundingMethodParameterName, newValue);
actualChanges.put("locale", localeAsInput);
loanProductInterestRecalculationDetails
.setInterestRecalculationCompoundingMethod(InterestRecalculationCompoundingMethod.fromInt(newValue).getValue());
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.rescheduleStrategyMethodParameterName,
loanProductInterestRecalculationDetails.getRescheduleStrategyMethod())) {
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.rescheduleStrategyMethodParameterName);
actualChanges.put(LoanProductConstants.rescheduleStrategyMethodParameterName, newValue);
actualChanges.put("locale", localeAsInput);
loanProductInterestRecalculationDetails.setRescheduleStrategyMethod(LoanRescheduleStrategyMethod.fromInt(newValue).getValue());
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationRestFrequencyTypeParameterName,
loanProductInterestRecalculationDetails.getRestFrequencyType().getValue())) {
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyTypeParameterName);
actualChanges.put(LoanProductConstants.recalculationRestFrequencyTypeParameterName, newValue);
actualChanges.put("locale", localeAsInput);
loanProductInterestRecalculationDetails.setRestFrequencyType(RecalculationFrequencyType.fromInt(newValue).getValue());
}
RecalculationFrequencyType frequencyType = loanProductInterestRecalculationDetails.getRestFrequencyType();
if (frequencyType.isSameAsRepayment()) {
loanProductInterestRecalculationDetails.setRestInterval(0);
loanProductInterestRecalculationDetails.setRestFrequencyNthDay(null);
loanProductInterestRecalculationDetails.setRestFrequencyWeekday(null);
loanProductInterestRecalculationDetails.setRestFrequencyOnDay(null);
} else {
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationRestFrequencyIntervalParameterName,
loanProductInterestRecalculationDetails.getRestInterval())) {
Integer newValue = command
.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyIntervalParameterName);
actualChanges.put(LoanProductConstants.recalculationRestFrequencyIntervalParameterName, newValue);
actualChanges.put("locale", localeAsInput);
loanProductInterestRecalculationDetails.setRestInterval(newValue);
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationRestFrequencyNthDayParamName,
loanProductInterestRecalculationDetails.getRestFrequencyNthDay())) {
Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyNthDayParamName);
actualChanges.put(LoanProductConstants.recalculationRestFrequencyNthDayParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanProductInterestRecalculationDetails.setRestFrequencyNthDay(newValue);
loanProductInterestRecalculationDetails.setRestFrequencyOnDay(null);
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationRestFrequencyWeekdayParamName,
loanProductInterestRecalculationDetails.getRestFrequencyWeekday())) {
Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyWeekdayParamName);
actualChanges.put(LoanProductConstants.recalculationRestFrequencyWeekdayParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanProductInterestRecalculationDetails.setRestFrequencyWeekday(newValue);
loanProductInterestRecalculationDetails.setRestFrequencyOnDay(null);
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationRestFrequencyOnDayParamName,
loanProductInterestRecalculationDetails.getRestFrequencyOnDay())) {
Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyOnDayParamName);
actualChanges.put(LoanProductConstants.recalculationRestFrequencyOnDayParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanProductInterestRecalculationDetails.setRestFrequencyOnDay(newValue);
loanProductInterestRecalculationDetails.setRestFrequencyNthDay(null);
loanProductInterestRecalculationDetails.setRestFrequencyWeekday(null);
}
if (frequencyType.isWeekly()) {
loanProductInterestRecalculationDetails.setRestFrequencyNthDay(null);
loanProductInterestRecalculationDetails.setRestFrequencyOnDay(null);
} else if (frequencyType.isMonthly()) {
if (command.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyOnDayParamName) != null) {
loanProductInterestRecalculationDetails.setRestFrequencyNthDay(null);
loanProductInterestRecalculationDetails.setRestFrequencyWeekday(null);
} else {
loanProductInterestRecalculationDetails.setRestFrequencyOnDay(null);
}
} else if (frequencyType.isDaily()) {
loanProductInterestRecalculationDetails.setRestFrequencyNthDay(null);
loanProductInterestRecalculationDetails.setRestFrequencyWeekday(null);
loanProductInterestRecalculationDetails.setRestFrequencyOnDay(null);
}
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyTypeParameterName,
loanProductInterestRecalculationDetails.getCompoundingFrequencyType().getValue())) {
final Integer newValue = command
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyTypeParameterName);
actualChanges.put(LoanProductConstants.recalculationCompoundingFrequencyTypeParameterName, newValue);
loanProductInterestRecalculationDetails.setCompoundingFrequencyType(RecalculationFrequencyType.fromInt(newValue).getValue());
}
InterestRecalculationCompoundingMethod compoundingMethod = InterestRecalculationCompoundingMethod
.fromInt(loanProductInterestRecalculationDetails.getInterestRecalculationCompoundingMethod());
if (compoundingMethod.isCompoundingEnabled()) {
RecalculationFrequencyType compoundingFrequencyType = loanProductInterestRecalculationDetails.getCompoundingFrequencyType();
if (compoundingFrequencyType.isSameAsRepayment()) {
loanProductInterestRecalculationDetails.setCompoundingInterval(null);
loanProductInterestRecalculationDetails.setCompoundingFrequencyNthDay(null);
loanProductInterestRecalculationDetails.setCompoundingFrequencyWeekday(null);
loanProductInterestRecalculationDetails.setCompoundingFrequencyOnDay(null);
} else {
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyIntervalParameterName,
loanProductInterestRecalculationDetails.getCompoundingInterval())) {
Integer newValue = command
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyIntervalParameterName);
actualChanges.put(LoanProductConstants.recalculationCompoundingFrequencyIntervalParameterName, newValue);
loanProductInterestRecalculationDetails.setCompoundingInterval(newValue);
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyNthDayParamName,
loanProductInterestRecalculationDetails.getCompoundingFrequencyNthDay())) {
Integer newValue = command
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyNthDayParamName);
actualChanges.put(LoanProductConstants.recalculationCompoundingFrequencyNthDayParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanProductInterestRecalculationDetails.setCompoundingFrequencyNthDay(newValue);
loanProductInterestRecalculationDetails.setCompoundingFrequencyOnDay(null);
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyWeekdayParamName,
loanProductInterestRecalculationDetails.getCompoundingFrequencyWeekday())) {
Integer newValue = command
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyWeekdayParamName);
actualChanges.put(LoanProductConstants.recalculationCompoundingFrequencyWeekdayParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanProductInterestRecalculationDetails.setCompoundingFrequencyWeekday(newValue);
loanProductInterestRecalculationDetails.setCompoundingFrequencyOnDay(null);
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyOnDayParamName,
loanProductInterestRecalculationDetails.getCompoundingFrequencyOnDay())) {
Integer newValue = command
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyOnDayParamName);
actualChanges.put(LoanProductConstants.recalculationCompoundingFrequencyOnDayParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanProductInterestRecalculationDetails.setCompoundingFrequencyOnDay(newValue);
loanProductInterestRecalculationDetails.setCompoundingFrequencyNthDay(null);
loanProductInterestRecalculationDetails.setCompoundingFrequencyWeekday(null);
}
if (compoundingFrequencyType.isWeekly()) {
loanProductInterestRecalculationDetails.setCompoundingFrequencyNthDay(null);
loanProductInterestRecalculationDetails.setCompoundingFrequencyOnDay(null);
} else if (compoundingFrequencyType.isMonthly()) {
if (command
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyOnDayParamName) != null) {
loanProductInterestRecalculationDetails.setCompoundingFrequencyNthDay(null);
loanProductInterestRecalculationDetails.setCompoundingFrequencyWeekday(null);
} else {
loanProductInterestRecalculationDetails.setCompoundingFrequencyOnDay(null);
}
} else if (compoundingFrequencyType.isDaily()) {
loanProductInterestRecalculationDetails.setCompoundingFrequencyNthDay(null);
loanProductInterestRecalculationDetails.setCompoundingFrequencyWeekday(null);
loanProductInterestRecalculationDetails.setCompoundingFrequencyOnDay(null);
}
}
if (!compoundingFrequencyType.isDaily()) {
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.allowCompoundingOnEodParamName,
loanProductInterestRecalculationDetails.getAllowCompoundingOnEod())) {
boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.allowCompoundingOnEodParamName);
actualChanges.put(LoanProductConstants.allowCompoundingOnEodParamName, newValue);
loanProductInterestRecalculationDetails.setAllowCompoundingOnEod(newValue);
}
} else {
loanProductInterestRecalculationDetails.setAllowCompoundingOnEod(false);
}
} else {
loanProductInterestRecalculationDetails.setCompoundingFrequencyType(null);
loanProductInterestRecalculationDetails.setCompoundingInterval(null);
loanProductInterestRecalculationDetails.setCompoundingFrequencyNthDay(null);
loanProductInterestRecalculationDetails.setCompoundingFrequencyWeekday(null);
loanProductInterestRecalculationDetails.setCompoundingFrequencyOnDay(null);
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.isArrearsBasedOnOriginalScheduleParamName,
loanProductInterestRecalculationDetails.isArrearsBasedOnOriginalSchedule())) {
final boolean newValue = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.isArrearsBasedOnOriginalScheduleParamName);
actualChanges.put(LoanProductConstants.isArrearsBasedOnOriginalScheduleParamName, newValue);
loanProductInterestRecalculationDetails.setArrearsBasedOnOriginalSchedule(newValue);
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.preClosureInterestCalculationStrategyParamName,
loanProductInterestRecalculationDetails.getPreCloseInterestCalculationStrategy().getValue())) {
Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.preClosureInterestCalculationStrategyParamName);
if (newValue == null) {
newValue = LoanPreCloseInterestCalculationStrategy.TILL_PRE_CLOSURE_DATE.getValue();
}
actualChanges.put(LoanProductConstants.preClosureInterestCalculationStrategyParamName, newValue);
loanProductInterestRecalculationDetails.setPreCloseInterestCalculationStrategy(newValue);
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.isCompoundingToBePostedAsTransactionParamName,
loanProductInterestRecalculationDetails.getIsCompoundingToBePostedAsTransaction())) {
final boolean newValue = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.isCompoundingToBePostedAsTransactionParamName);
actualChanges.put(LoanProductConstants.isCompoundingToBePostedAsTransactionParamName, newValue);
loanProductInterestRecalculationDetails.setIsCompoundingToBePostedAsTransaction(newValue);
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.disallowInterestCalculationOnPastDueParamName,
loanProductInterestRecalculationDetails.getDisallowInterestCalculationOnPastDue())) {
final boolean newValue = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.disallowInterestCalculationOnPastDueParamName);
actualChanges.put(LoanProductConstants.disallowInterestCalculationOnPastDueParamName, newValue);
loanProductInterestRecalculationDetails.setDisallowInterestCalculationOnPastDue(newValue);
}
}
}
@@ -0,0 +1,95 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.loanaccount.service;
import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductMinMaxConstraints;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class LoanProductMinMaxConstraintsUpdateUtil {
public Map<String, Object> update(final LoanProductMinMaxConstraints loanProductMinMaxConstraints, final JsonCommand command) {
final Map<String, Object> actualChanges = new LinkedHashMap<>(20);
final String localeAsInput = command.locale();
final String minPrincipalParamName = "minPrincipal";
if (command.isChangeInBigDecimalParameterNamedWithNullCheck(minPrincipalParamName,
loanProductMinMaxConstraints.getMinPrincipal())) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(minPrincipalParamName);
actualChanges.put(minPrincipalParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanProductMinMaxConstraints.setMinPrincipal(newValue);
}
final String maxPrincipalParamName = "maxPrincipal";
if (command.isChangeInBigDecimalParameterNamedWithNullCheck(maxPrincipalParamName,
loanProductMinMaxConstraints.getMaxPrincipal())) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(maxPrincipalParamName);
actualChanges.put(maxPrincipalParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanProductMinMaxConstraints.setMaxPrincipal(newValue);
}
final String minNumberOfRepaymentsParamName = "minNumberOfRepayments";
if (command.isChangeInIntegerParameterNamed(minNumberOfRepaymentsParamName,
loanProductMinMaxConstraints.getMinNumberOfRepayments())) {
final Integer newValue = command.integerValueOfParameterNamed(minNumberOfRepaymentsParamName);
actualChanges.put(minNumberOfRepaymentsParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanProductMinMaxConstraints.setMinNumberOfRepayments(newValue);
}
final String maxNumberOfRepaymentsParamName = "maxNumberOfRepayments";
if (command.isChangeInIntegerParameterNamed(maxNumberOfRepaymentsParamName,
loanProductMinMaxConstraints.getMaxNumberOfRepayments())) {
final Integer newValue = command.integerValueOfParameterNamed(maxNumberOfRepaymentsParamName);
actualChanges.put(maxNumberOfRepaymentsParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanProductMinMaxConstraints.setMaxNumberOfRepayments(newValue);
}
final String minInterestRatePerPeriodParamName = "minInterestRatePerPeriod";
if (command.isChangeInBigDecimalParameterNamedWithNullCheck(minInterestRatePerPeriodParamName,
loanProductMinMaxConstraints.getMinNominalInterestRatePerPeriod())) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(minInterestRatePerPeriodParamName);
actualChanges.put(minInterestRatePerPeriodParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanProductMinMaxConstraints.setMinNominalInterestRatePerPeriod(newValue);
}
final String maxInterestRatePerPeriodParamName = "maxInterestRatePerPeriod";
if (command.isChangeInBigDecimalParameterNamedWithNullCheck(maxInterestRatePerPeriodParamName,
loanProductMinMaxConstraints.getMaxNominalInterestRatePerPeriod())) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(maxInterestRatePerPeriodParamName);
actualChanges.put(maxInterestRatePerPeriodParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanProductMinMaxConstraints.setMaxNominalInterestRatePerPeriod(newValue);
}
return actualChanges;
}
}
@@ -0,0 +1,309 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.loanaccount.service;
import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.portfolio.common.domain.DaysInYearCustomStrategyType;
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
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;
import org.apache.fineract.portfolio.loanproduct.domain.AmortizationMethod;
import org.apache.fineract.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class LoanProductRelatedDetailUpdateUtil {
public Map<String, Object> updateLoanRepaymentSchedule(final LoanProductRelatedDetail loanRepaymentScheduleDetail,
final JsonCommand command, final AprCalculator aprCalculator) {
final Map<String, Object> actualChanges = new LinkedHashMap<>(20);
final String localeAsInput = command.locale();
String currencyCode = loanRepaymentScheduleDetail.getCurrency().getCode();
Integer digitsAfterDecimal = loanRepaymentScheduleDetail.getCurrency().getDigitsAfterDecimal();
Integer inMultiplesOf = loanRepaymentScheduleDetail.getCurrency().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;
loanRepaymentScheduleDetail.setCurrency(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;
loanRepaymentScheduleDetail.setCurrency(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;
loanRepaymentScheduleDetail.setCurrency(new MonetaryCurrency(currencyCode, digitsAfterDecimal, inMultiplesOf));
}
final String loanScheduleTypeParamName = LoanProductConstants.LOAN_SCHEDULE_TYPE;
if (command.isChangeInStringParameterNamed(loanScheduleTypeParamName,
loanRepaymentScheduleDetail.getLoanScheduleType().toString())) {
LoanScheduleType newLoanScheduleType = LoanScheduleType.valueOf(command.stringValueOfParameterNamed(loanScheduleTypeParamName));
actualChanges.put(loanScheduleTypeParamName, newLoanScheduleType);
loanRepaymentScheduleDetail.setLoanScheduleType(newLoanScheduleType);
}
final String loanScheduleProcessingTypeParamName = LoanProductConstants.LOAN_SCHEDULE_PROCESSING_TYPE;
if (command.isChangeInStringParameterNamed(loanScheduleProcessingTypeParamName,
loanRepaymentScheduleDetail.getLoanScheduleProcessingType().toString())) {
LoanScheduleProcessingType newLoanScheduleProcessingType = LoanScheduleProcessingType
.valueOf(command.stringValueOfParameterNamed(loanScheduleProcessingTypeParamName));
actualChanges.put(loanScheduleProcessingTypeParamName, newLoanScheduleProcessingType);
loanRepaymentScheduleDetail.setLoanScheduleProcessingType(newLoanScheduleProcessingType);
}
final String principalParamName = "principal";
if (command.isChangeInBigDecimalParameterNamed(principalParamName, loanRepaymentScheduleDetail.getPrincipal().getAmount())) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(principalParamName);
actualChanges.put(principalParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanRepaymentScheduleDetail.setPrincipal(newValue);
}
final String repaymentEveryParamName = "repaymentEvery";
if (command.isChangeInIntegerParameterNamed(repaymentEveryParamName, loanRepaymentScheduleDetail.getRepayEvery())) {
final Integer newValue = command.integerValueOfParameterNamed(repaymentEveryParamName);
actualChanges.put(repaymentEveryParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanRepaymentScheduleDetail.setRepayEvery(newValue);
}
final String repaymentFrequencyTypeParamName = "repaymentFrequencyType";
if (command.isChangeInIntegerParameterNamed(repaymentFrequencyTypeParamName,
loanRepaymentScheduleDetail.getRepaymentPeriodFrequencyType().getValue())) {
Integer newValue = command.integerValueOfParameterNamed(repaymentFrequencyTypeParamName);
actualChanges.put(repaymentFrequencyTypeParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanRepaymentScheduleDetail.setRepaymentPeriodFrequencyType(PeriodFrequencyType.fromInt(newValue));
}
if (loanRepaymentScheduleDetail.getRepaymentPeriodFrequencyType() == PeriodFrequencyType.MONTHS) {
final String repaymentFrequencyNthDayTypeParamName = "repaymentFrequencyNthDayType";
Integer 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, loanRepaymentScheduleDetail.getNumberOfRepayments())) {
final Integer newValue = command.integerValueOfParameterNamed(numberOfRepaymentsParamName);
actualChanges.put(numberOfRepaymentsParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanRepaymentScheduleDetail.setNumberOfRepayments(newValue);
}
final String amortizationTypeParamName = "amortizationType";
if (command.isChangeInIntegerParameterNamed(amortizationTypeParamName,
loanRepaymentScheduleDetail.getAmortizationMethod().getValue())) {
final Integer newValue = command.integerValueOfParameterNamed(amortizationTypeParamName);
actualChanges.put(amortizationTypeParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanRepaymentScheduleDetail.setAmortizationMethod(AmortizationMethod.fromInt(newValue));
}
final String inArrearsToleranceParamName = "inArrearsTolerance";
if (command.isChangeInBigDecimalParameterNamed(inArrearsToleranceParamName,
loanRepaymentScheduleDetail.getInArrearsTolerance().getAmount())) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(inArrearsToleranceParamName);
actualChanges.put(inArrearsToleranceParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanRepaymentScheduleDetail.setInArrearsTolerance(newValue);
}
final String interestRatePerPeriodParamName = "interestRatePerPeriod";
if (command.isChangeInBigDecimalParameterNamed(interestRatePerPeriodParamName,
loanRepaymentScheduleDetail.getNominalInterestRatePerPeriod())) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(interestRatePerPeriodParamName);
actualChanges.put(interestRatePerPeriodParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanRepaymentScheduleDetail.setNominalInterestRatePerPeriod(newValue);
updateInterestRateDerivedFields(loanRepaymentScheduleDetail, aprCalculator);
}
final String interestRateFrequencyTypeParamName = "interestRateFrequencyType";
final int interestPeriodFrequencyType = loanRepaymentScheduleDetail.getInterestPeriodFrequencyType() == null
? PeriodFrequencyType.INVALID.getValue()
: loanRepaymentScheduleDetail.getInterestPeriodFrequencyType().getValue();
if (command.isChangeInIntegerParameterNamed(interestRateFrequencyTypeParamName, interestPeriodFrequencyType)) {
final Integer newValue = command.integerValueOfParameterNamed(interestRateFrequencyTypeParamName);
actualChanges.put(interestRateFrequencyTypeParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanRepaymentScheduleDetail.setInterestPeriodFrequencyType(PeriodFrequencyType.fromInt(newValue));
updateInterestRateDerivedFields(loanRepaymentScheduleDetail, aprCalculator);
}
final String interestTypeParamName = "interestType";
if (command.isChangeInIntegerParameterNamed(interestTypeParamName, loanRepaymentScheduleDetail.getInterestMethod().getValue())) {
final Integer newValue = command.integerValueOfParameterNamed(interestTypeParamName);
actualChanges.put(interestTypeParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanRepaymentScheduleDetail.setInterestMethod(InterestMethod.fromInt(newValue));
}
final String interestCalculationPeriodTypeParamName = "interestCalculationPeriodType";
if (command.isChangeInIntegerParameterNamed(interestCalculationPeriodTypeParamName,
loanRepaymentScheduleDetail.getInterestCalculationPeriodMethod().getValue())) {
final Integer newValue = command.integerValueOfParameterNamed(interestCalculationPeriodTypeParamName);
actualChanges.put(interestCalculationPeriodTypeParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanRepaymentScheduleDetail.setInterestCalculationPeriodMethod(InterestCalculationPeriodMethod.fromInt(newValue));
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.ALLOW_PARTIAL_PERIOD_INTEREST_CALCUALTION_PARAM_NAME,
loanRepaymentScheduleDetail.isAllowPartialPeriodInterestCalcualtion())) {
final boolean newValue = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ALLOW_PARTIAL_PERIOD_INTEREST_CALCUALTION_PARAM_NAME);
actualChanges.put(LoanProductConstants.ALLOW_PARTIAL_PERIOD_INTEREST_CALCUALTION_PARAM_NAME, newValue);
loanRepaymentScheduleDetail.setAllowPartialPeriodInterestCalcualtion(newValue);
}
if (loanRepaymentScheduleDetail.getInterestCalculationPeriodMethod().isDaily()) {
loanRepaymentScheduleDetail.setAllowPartialPeriodInterestCalcualtion(false);
}
final String graceOnPrincipalPaymentParamName = "graceOnPrincipalPayment";
if (command.isChangeInIntegerParameterNamed(graceOnPrincipalPaymentParamName,
loanRepaymentScheduleDetail.getGraceOnPrincipalPayment())) {
final Integer newValue = command.integerValueOfParameterNamed(graceOnPrincipalPaymentParamName);
actualChanges.put(graceOnPrincipalPaymentParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanRepaymentScheduleDetail.setGraceOnPrincipalPayment(newValue);
}
final String recurringMoratoriumOnPrincipalPeriodsParamName = "recurringMoratoriumOnPrincipalPeriods";
if (command.isChangeInIntegerParameterNamed(recurringMoratoriumOnPrincipalPeriodsParamName,
loanRepaymentScheduleDetail.getRecurringMoratoriumOnPrincipalPeriods())) {
final Integer newValue = command.integerValueOfParameterNamed(recurringMoratoriumOnPrincipalPeriodsParamName);
actualChanges.put(recurringMoratoriumOnPrincipalPeriodsParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanRepaymentScheduleDetail.setRecurringMoratoriumOnPrincipalPeriods(newValue);
}
final String graceOnInterestPaymentParamName = "graceOnInterestPayment";
if (command.isChangeInIntegerParameterNamed(graceOnInterestPaymentParamName,
loanRepaymentScheduleDetail.getGraceOnInterestPayment())) {
final Integer newValue = command.integerValueOfParameterNamed(graceOnInterestPaymentParamName);
actualChanges.put(graceOnInterestPaymentParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanRepaymentScheduleDetail.setGraceOnInterestPayment(newValue);
}
final String graceOnInterestChargedParamName = "graceOnInterestCharged";
if (command.isChangeInIntegerParameterNamed(graceOnInterestChargedParamName,
loanRepaymentScheduleDetail.getGraceOnInterestCharged())) {
final Integer newValue = command.integerValueOfParameterNamed(graceOnInterestChargedParamName);
actualChanges.put(graceOnInterestChargedParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanRepaymentScheduleDetail.setGraceOnInterestCharged(newValue);
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.GRACE_ON_ARREARS_AGEING_PARAMETER_NAME,
loanRepaymentScheduleDetail.getGraceOnArrearsAgeing())) {
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);
loanRepaymentScheduleDetail.setGraceOnArrearsAgeing(newValue);
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.DAYS_IN_MONTH_TYPE_PARAMETER_NAME,
loanRepaymentScheduleDetail.getDaysInMonthType())) {
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);
loanRepaymentScheduleDetail.setDaysInMonthType(newValue);
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.DAYS_IN_YEAR_TYPE_PARAMETER_NAME,
loanRepaymentScheduleDetail.getDaysInYearType())) {
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);
loanRepaymentScheduleDetail.setDaysInYearType(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());
loanRepaymentScheduleDetail.setDaysInYearCustomStrategy(newValue);
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.IS_INTEREST_RECALCULATION_ENABLED_PARAMETER_NAME,
loanRepaymentScheduleDetail.isInterestRecalculationEnabled())) {
final boolean newValue = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.IS_INTEREST_RECALCULATION_ENABLED_PARAMETER_NAME);
actualChanges.put(LoanProductConstants.IS_INTEREST_RECALCULATION_ENABLED_PARAMETER_NAME, newValue);
loanRepaymentScheduleDetail.setInterestRecalculationEnabled(newValue);
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM,
loanRepaymentScheduleDetail.isEqualAmortization())) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM);
actualChanges.put(LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM, newValue);
loanRepaymentScheduleDetail.setEqualAmortization(newValue);
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE,
loanRepaymentScheduleDetail.isInterestRecognitionOnDisbursementDate())) {
final boolean newValue = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE);
actualChanges.put(LoanProductConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE, newValue);
loanRepaymentScheduleDetail.updateInterestRecognitionOnDisbursementDate(newValue);
}
return actualChanges;
}
public void updateInterestRateDerivedFields(final LoanProductRelatedDetail loanRepaymentScheduleDetail,
final AprCalculator aprCalculator) {
BigDecimal annualNominalInterestRate = aprCalculator.calculateFrom(loanRepaymentScheduleDetail.getInterestPeriodFrequencyType(),
loanRepaymentScheduleDetail.getNominalInterestRatePerPeriod(), loanRepaymentScheduleDetail.getNumberOfRepayments(),
loanRepaymentScheduleDetail.getRepayEvery(), loanRepaymentScheduleDetail.getRepaymentPeriodFrequencyType());
loanRepaymentScheduleDetail.setAnnualNominalInterestRate(annualNominalInterestRate);
}
}
@@ -0,0 +1,62 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.loanaccount.service;
import java.math.BigDecimal;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductTrancheDetails;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class LoanProductTrancheDetailsUpdateUtil {
public void update(final LoanProductTrancheDetails loanProductTrancheDetails, final JsonCommand command,
final Map<String, Object> actualChanges) {
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.MULTI_DISBURSE_LOAN_PARAMETER_NAME,
loanProductTrancheDetails.isMultiDisburseLoan())) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.MULTI_DISBURSE_LOAN_PARAMETER_NAME);
actualChanges.put(LoanProductConstants.MULTI_DISBURSE_LOAN_PARAMETER_NAME, newValue);
loanProductTrancheDetails.setMultiDisburseLoan(newValue);
}
if (loanProductTrancheDetails.isMultiDisburseLoan()) {
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.MAX_TRANCHE_COUNT_PARAMETER_NAME,
loanProductTrancheDetails.getMaxTrancheCount())) {
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.MAX_TRANCHE_COUNT_PARAMETER_NAME);
actualChanges.put(LoanProductConstants.MAX_TRANCHE_COUNT_PARAMETER_NAME, newValue);
loanProductTrancheDetails.setMaxTrancheCount(newValue);
}
if (command.isChangeInBigDecimalParameterNamed(LoanProductConstants.OUTSTANDING_LOAN_BALANCE_PARAMETER_NAME,
loanProductTrancheDetails.getOutstandingLoanBalance())) {
final BigDecimal newValue = command
.bigDecimalValueOfParameterNamed(LoanProductConstants.OUTSTANDING_LOAN_BALANCE_PARAMETER_NAME);
actualChanges.put(LoanProductConstants.OUTSTANDING_LOAN_BALANCE_PARAMETER_NAME, newValue);
loanProductTrancheDetails.setOutstandingLoanBalance(newValue);
}
} else {
loanProductTrancheDetails.setMaxTrancheCount(null);
loanProductTrancheDetails.setOutstandingLoanBalance(null);
}
}
}
@@ -0,0 +1,632 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.loanaccount.service;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import lombok.RequiredArgsConstructor;
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.ExternalId;
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
import org.apache.fineract.portfolio.floatingrates.domain.FloatingRate;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.AprCalculator;
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductBorrowerCycleVariations;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductConfigurableAttributes;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductParamType;
import org.apache.fineract.portfolio.loanproduct.domain.RepaymentStartDateType;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class LoanProductUpdateUtil {
private final LoanProductRelatedDetailUpdateUtil detailUpdateUtil;
private final LoanProductMinMaxConstraintsUpdateUtil minMaxConstraintsUpdateUtil;
private final LoanProductFloatingRatesUpdateUtil floatingRatesUpdateUtil;
private final LoanProductVariableInstallmentConfigUpdateUtil variableInstallmentConfigUpdateUtil;
private final LoanProductTrancheDetailsUpdateUtil trancheDetailsUpdateUtil;
private final LoanProductInterestRecalculationDetailsAssembler interestRecalculationDetailsAssembler;
private final LoanProductInterestRecalculationDetailsUpdateUtil interestRecalculationDetailsUpdateUtil;
private final LoanProductGuaranteeDetailsAssembler guaranteeDetailsAssembler;
private final LoanProductGuaranteeDetailsUpdateUtil guaranteeDetailsUpdateUtil;
public Map<String, Object> update(final LoanProduct loanProduct, final JsonCommand command, final AprCalculator aprCalculator,
FloatingRate floatingRate) {
final Map<String, Object> actualChanges = detailUpdateUtil.updateLoanRepaymentSchedule(loanProduct.getLoanProductRelatedDetail(),
command, aprCalculator);
actualChanges.putAll(minMaxConstraintsUpdateUtil.update(loanProduct.loanProductMinMaxConstraints(), command));
final String isLinkedToFloatingInterestRates = "isLinkedToFloatingInterestRates";
if (command.isChangeInBooleanParameterNamed(isLinkedToFloatingInterestRates, loanProduct.isLinkedToFloatingInterestRate())) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(isLinkedToFloatingInterestRates);
actualChanges.put(isLinkedToFloatingInterestRates, newValue);
loanProduct.setLinkedToFloatingInterestRate(newValue);
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.ENABLE_ACCRUAL_ACTIVITY_POSTING,
loanProduct.getLoanProductRelatedDetail().isEnableAccrualActivityPosting())) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ENABLE_ACCRUAL_ACTIVITY_POSTING);
actualChanges.put(LoanProductConstants.ENABLE_ACCRUAL_ACTIVITY_POSTING, newValue);
loanProduct.getLoanProductRelatedDetail().setEnableAccrualActivityPosting(newValue);
}
if (loanProduct.isLinkedToFloatingInterestRate()) {
actualChanges.putAll(floatingRatesUpdateUtil.update(loanProduct.loanProductFloatingRates(), command, floatingRate));
loanProduct.getLoanProductRelatedDetail().updateForFloatingInterestRates();
loanProduct.getLoanProductMinMaxConstraints().updateForFloatingInterestRates();
} else {
loanProduct.setFloatingRates(null);
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.allowVariableInstallmentsParamName,
loanProduct.isAllowVariabeInstallments())) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.allowVariableInstallmentsParamName);
actualChanges.put(LoanProductConstants.allowVariableInstallmentsParamName, newValue);
loanProduct.setAllowVariabeInstallments(newValue);
}
if (loanProduct.isAllowVariabeInstallments()) {
actualChanges.putAll(variableInstallmentConfigUpdateUtil.update(loanProduct.loanProductVariableInstallmentConfig(), command));
} else {
loanProduct.setVariableInstallmentConfig(null);
}
final String accountingTypeParamName = "accountingRule";
Integer currentValue = loanProduct.getAccountingRule() == null ? null : loanProduct.getAccountingRule().getValue();
if (command.isChangeInIntegerParameterNamed(accountingTypeParamName, currentValue)) {
final Integer newValue = command.integerValueOfParameterNamed(accountingTypeParamName);
actualChanges.put(accountingTypeParamName, newValue);
loanProduct.setAccountingRule(AccountingRuleType.fromInt(newValue));
}
final String nameParamName = "name";
if (command.isChangeInStringParameterNamed(nameParamName, loanProduct.getName())) {
final String newValue = command.stringValueOfParameterNamed(nameParamName);
actualChanges.put(nameParamName, newValue);
loanProduct.setName(newValue);
}
final String shortNameParamName = LoanProductConstants.SHORT_NAME;
if (command.isChangeInStringParameterNamed(shortNameParamName, loanProduct.getShortName())) {
final String newValue = command.stringValueOfParameterNamed(shortNameParamName);
actualChanges.put(shortNameParamName, newValue);
loanProduct.setShortName(newValue);
}
final String descriptionParamName = "description";
if (command.isChangeInStringParameterNamed(descriptionParamName, loanProduct.getDescription())) {
final String newValue = command.stringValueOfParameterNamed(descriptionParamName);
actualChanges.put(descriptionParamName, newValue);
loanProduct.setDescription(newValue);
}
Long existingFundId = null;
if (loanProduct.getFund() != null) {
existingFundId = loanProduct.getFund().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,
loanProduct.getTransactionProcessingStrategyCode())) {
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, loanProduct.isIncludeInBorrowerCycle())) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(includeInBorrowerCycleParamName);
actualChanges.put(includeInBorrowerCycleParamName, newValue);
loanProduct.setIncludeInBorrowerCycle(newValue);
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.USE_BORROWER_CYCLE_PARAMETER_NAME,
loanProduct.isUseBorrowerCycle())) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.USE_BORROWER_CYCLE_PARAMETER_NAME);
actualChanges.put(LoanProductConstants.USE_BORROWER_CYCLE_PARAMETER_NAME, newValue);
loanProduct.setUseBorrowerCycle(newValue);
}
if (loanProduct.isUseBorrowerCycle()) {
actualChanges.putAll(updateBorrowerCycleVariations(loanProduct, command));
} else {
clearVariations(loanProduct);
}
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, loanProduct.getStartDate())) {
final String valueAsInput = command.stringValueOfParameterNamed(startDateParamName);
actualChanges.put(startDateParamName, valueAsInput);
actualChanges.put(dateFormatParamName, dateFormatAsInput);
actualChanges.put(localeParamName, localeAsInput);
loanProduct.setStartDate(command.localDateValueOfParameterNamed(startDateParamName));
}
final String closeDateParamName = "closeDate";
if (command.isChangeInLocalDateParameterNamed(closeDateParamName, loanProduct.getCloseDate())) {
final String valueAsInput = command.stringValueOfParameterNamed(closeDateParamName);
actualChanges.put(closeDateParamName, valueAsInput);
actualChanges.put(dateFormatParamName, dateFormatAsInput);
actualChanges.put(localeParamName, localeAsInput);
loanProduct.setCloseDate(command.localDateValueOfParameterNamed(closeDateParamName));
}
final String externalIdTypeParamName = "externalId";
if (command.isChangeInExternalIdParameterNamed(externalIdTypeParamName, loanProduct.getExternalId())) {
final ExternalId newValue = ExternalIdFactory.produce(command.stringValueOfParameterNamed(externalIdTypeParamName));
actualChanges.put(accountingTypeParamName, newValue);
loanProduct.setExternalId(newValue);
}
trancheDetailsUpdateUtil.update(loanProduct.getLoanProductTrancheDetails(), command, actualChanges);
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.OVERDUE_DAYS_FOR_NPA_PARAMETER_NAME,
loanProduct.getOverdueDaysForNPA())) {
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);
loanProduct.setOverdueDaysForNPA(newValue);
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.MINIMUM_DAYS_BETWEEN_DISBURSAL_AND_FIRST_REPAYMENT,
loanProduct.getMinimumDaysBetweenDisbursalAndFirstRepayment())) {
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);
loanProduct.setMinimumDaysBetweenDisbursalAndFirstRepayment(newValue);
}
if (command.isChangeInBooleanParameterNamed("syncExpectedWithDisbursementDate", loanProduct.isSyncExpectedWithDisbursementDate())) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed("syncExpectedWithDisbursementDate");
actualChanges.put("syncExpectedWithDisbursementDate", newValue);
loanProduct.setSyncExpectedWithDisbursementDate(newValue);
}
Long delinquencyBucketId = null;
if (loanProduct.getDelinquencyBucket() != null) {
delinquencyBucketId = loanProduct.getDelinquencyBucket().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 (loanProduct.isInterestRecalculationEnabled()) {
loanProduct.setProductInterestRecalculationDetails(interestRecalculationDetailsAssembler.createFrom(command));
loanProduct.getProductInterestRecalculationDetails().updateProduct(loanProduct);
actualChanges.put(LoanProductConstants.interestRecalculationCompoundingMethodParameterName,
command.integerValueOfParameterNamed(LoanProductConstants.interestRecalculationCompoundingMethodParameterName));
actualChanges.put(LoanProductConstants.rescheduleStrategyMethodParameterName,
command.integerValueOfParameterNamed(LoanProductConstants.rescheduleStrategyMethodParameterName));
} else {
loanProduct.setProductInterestRecalculationDetails(null);
}
}
if (!isInterestRecalculationEnabledChanged && loanProduct.isInterestRecalculationEnabled()) {
interestRecalculationDetailsUpdateUtil.update(loanProduct.getProductInterestRecalculationDetails(), command, actualChanges,
localeAsInput);
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.holdGuaranteeFundsParamName, loanProduct.isHoldGuaranteeFunds())) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.holdGuaranteeFundsParamName);
actualChanges.put(LoanProductConstants.holdGuaranteeFundsParamName, newValue);
loanProduct.setHoldGuaranteeFunds(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() != loanProduct.getLoanConfigurableAttributes().getAmortizationBoolean()) {
loanProduct.getLoanConfigurableAttributes()
.setAmortizationType(command.parsedJson().getAsJsonObject()
.getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.amortizationTypeParamName).getAsBoolean());
}
if (command.parsedJson().getAsJsonObject().getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.interestTypeParamName)
.getAsBoolean() != loanProduct.getLoanConfigurableAttributes().getInterestMethodBoolean()) {
loanProduct.getLoanConfigurableAttributes()
.setInterestType(command.parsedJson().getAsJsonObject()
.getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.interestTypeParamName).getAsBoolean());
}
if (command.parsedJson().getAsJsonObject().getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.transactionProcessingStrategyCodeParamName)
.getAsBoolean() != loanProduct.getLoanConfigurableAttributes().getTransactionProcessingStrategyBoolean()) {
loanProduct.getLoanConfigurableAttributes()
.setTransactionProcessingStrategyCode(command.parsedJson().getAsJsonObject()
.getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.transactionProcessingStrategyCodeParamName).getAsBoolean());
}
if (command.parsedJson().getAsJsonObject().getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.interestCalculationPeriodTypeParamName)
.getAsBoolean() != loanProduct.getLoanConfigurableAttributes().getInterestCalcPeriodBoolean()) {
loanProduct.getLoanConfigurableAttributes()
.setInterestCalculationPeriodType(command.parsedJson().getAsJsonObject()
.getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.interestCalculationPeriodTypeParamName).getAsBoolean());
}
if (command.parsedJson().getAsJsonObject().getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.inArrearsToleranceParamName)
.getAsBoolean() != loanProduct.getLoanConfigurableAttributes().getArrearsToleranceBoolean()) {
loanProduct.getLoanConfigurableAttributes()
.setInArrearsTolerance(command.parsedJson().getAsJsonObject()
.getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.inArrearsToleranceParamName).getAsBoolean());
}
if (command.parsedJson().getAsJsonObject().getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.repaymentEveryParamName)
.getAsBoolean() != loanProduct.getLoanConfigurableAttributes().getRepaymentEveryBoolean()) {
loanProduct.getLoanConfigurableAttributes()
.setRepaymentEvery(command.parsedJson().getAsJsonObject()
.getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.repaymentEveryParamName).getAsBoolean());
}
if (command.parsedJson().getAsJsonObject().getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.graceOnPrincipalAndInterestPaymentParamName)
.getAsBoolean() != loanProduct.getLoanConfigurableAttributes().getGraceOnPrincipalAndInterestPaymentBoolean()) {
loanProduct.getLoanConfigurableAttributes()
.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() != loanProduct.getLoanConfigurableAttributes().getGraceOnArrearsAgingBoolean()) {
loanProduct.getLoanConfigurableAttributes()
.setGraceOnArrearsAgeing(command.parsedJson().getAsJsonObject()
.getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
.getAsJsonPrimitive(LoanProductConstants.GRACE_ON_ARREARS_AGEING_PARAMETER_NAME).getAsBoolean());
}
} else {
loanProduct.setLoanConfigurableAttributes(LoanProductConfigurableAttributes.populateDefaultsForConfigurableAttributes());
loanProduct.getLoanConfigurableAttributes().updateLoanProduct(loanProduct);
}
}
if (actualChanges.containsKey(LoanProductConstants.holdGuaranteeFundsParamName)) {
if (loanProduct.isHoldGuaranteeFunds()) {
loanProduct.setLoanProductGuaranteeDetails(guaranteeDetailsAssembler.createFrom(command));
loanProduct.getLoanProductGuaranteeDetails().updateProduct(loanProduct);
actualChanges.put(LoanProductConstants.mandatoryGuaranteeParamName,
loanProduct.getLoanProductGuaranteeDetails().getMandatoryGuarantee());
actualChanges.put(LoanProductConstants.minimumGuaranteeFromGuarantorParamName,
loanProduct.getLoanProductGuaranteeDetails().getMinimumGuaranteeFromGuarantor());
actualChanges.put(LoanProductConstants.minimumGuaranteeFromOwnFundsParamName,
loanProduct.getLoanProductGuaranteeDetails().getMinimumGuaranteeFromOwnFunds());
} else {
loanProduct.setLoanProductRelatedDetail(null);
}
} else if (loanProduct.isHoldGuaranteeFunds()) {
guaranteeDetailsUpdateUtil.update(loanProduct.getLoanProductGuaranteeDetails(), command, actualChanges);
}
if (command.isChangeInBigDecimalParameterNamed(LoanProductConstants.principalThresholdForLastInstallmentParamName,
loanProduct.getPrincipalThresholdForLastInstallment())) {
BigDecimal newValue = command
.bigDecimalValueOfParameterNamed(LoanProductConstants.principalThresholdForLastInstallmentParamName);
actualChanges.put(LoanProductConstants.principalThresholdForLastInstallmentParamName, newValue);
loanProduct.setPrincipalThresholdForLastInstallment(newValue);
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.ACCOUNT_MOVES_OUT_OF_NPA_ONLY_ON_ARREARS_COMPLETION_PARAM_NAME,
loanProduct.isAccountMovesOutOfNPAOnlyOnArrearsCompletion())) {
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);
loanProduct.setAccountMovesOutOfNPAOnlyOnArrearsCompletion(newValue);
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.canDefineEmiAmountParamName,
loanProduct.isCanDefineInstallmentAmount())) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.canDefineEmiAmountParamName);
actualChanges.put(LoanProductConstants.canDefineEmiAmountParamName, newValue);
loanProduct.setCanDefineInstallmentAmount(newValue);
}
if (command.isChangeInIntegerParameterNamedWithNullCheck(LoanProductConstants.installmentAmountInMultiplesOfParamName,
loanProduct.getInstallmentAmountInMultiplesOf())) {
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.installmentAmountInMultiplesOfParamName);
actualChanges.put(LoanProductConstants.installmentAmountInMultiplesOfParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanProduct.setInstallmentAmountInMultiplesOf(newValue);
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.CAN_USE_FOR_TOPUP, loanProduct.isCanUseForTopup())) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.CAN_USE_FOR_TOPUP);
actualChanges.put(LoanProductConstants.CAN_USE_FOR_TOPUP, newValue);
loanProduct.setCanUseForTopup(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,
loanProduct.getFixedPrincipalPercentagePerInstallment())) {
BigDecimal newValue = command
.bigDecimalValueOfParameterNamed(LoanProductConstants.fixedPrincipalPercentagePerInstallmentParamName);
actualChanges.put(LoanProductConstants.fixedPrincipalPercentagePerInstallmentParamName, newValue);
loanProduct.setFixedPrincipalPercentagePerInstallment(newValue);
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.DISALLOW_EXPECTED_DISBURSEMENTS,
loanProduct.isDisallowExpectedDisbursements())) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.DISALLOW_EXPECTED_DISBURSEMENTS);
actualChanges.put(LoanProductConstants.DISALLOW_EXPECTED_DISBURSEMENTS, newValue);
loanProduct.setDisallowExpectedDisbursements(newValue);
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.ALLOW_APPROVED_DISBURSED_AMOUNTS_OVER_APPLIED,
loanProduct.isAllowApprovedDisbursedAmountsOverApplied())) {
final boolean newValue = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ALLOW_APPROVED_DISBURSED_AMOUNTS_OVER_APPLIED);
actualChanges.put(LoanProductConstants.ALLOW_APPROVED_DISBURSED_AMOUNTS_OVER_APPLIED, newValue);
loanProduct.setAllowApprovedDisbursedAmountsOverApplied(newValue);
}
if (command.isChangeInStringParameterNamed(LoanProductConstants.OVER_APPLIED_CALCULATION_TYPE,
loanProduct.getOverAppliedCalculationType())) {
final String newValue = command.stringValueOfParameterNamed(LoanProductConstants.OVER_APPLIED_CALCULATION_TYPE);
actualChanges.put(LoanProductConstants.OVER_APPLIED_CALCULATION_TYPE, newValue);
loanProduct.setOverAppliedCalculationType(newValue);
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.OVER_APPLIED_NUMBER, loanProduct.getOverAppliedNumber())) {
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.OVER_APPLIED_NUMBER);
actualChanges.put(LoanProductConstants.OVER_APPLIED_NUMBER, newValue);
actualChanges.put("locale", localeAsInput);
loanProduct.setOverAppliedNumber(newValue);
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.DUE_DAYS_FOR_REPAYMENT_EVENT,
loanProduct.getDueDaysForRepaymentEvent())) {
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.DUE_DAYS_FOR_REPAYMENT_EVENT);
actualChanges.put(LoanProductConstants.DUE_DAYS_FOR_REPAYMENT_EVENT, newValue);
actualChanges.put("locale", localeAsInput);
loanProduct.setDueDaysForRepaymentEvent(newValue);
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.OVER_DUE_DAYS_FOR_REPAYMENT_EVENT,
loanProduct.getOverDueDaysForRepaymentEvent())) {
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);
loanProduct.setOverDueDaysForRepaymentEvent(newValue);
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.ENABLE_DOWN_PAYMENT,
loanProduct.getLoanProductRelatedDetail().isEnableDownPayment())) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ENABLE_DOWN_PAYMENT);
actualChanges.put(LoanProductConstants.ENABLE_DOWN_PAYMENT, newValue);
loanProduct.getLoanProductRelatedDetail().setEnableDownPayment(newValue);
}
if (command.isChangeInBigDecimalParameterNamed(LoanProductConstants.DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT,
loanProduct.getLoanProductRelatedDetail().getDisbursedAmountPercentageForDownPayment())) {
BigDecimal newValue = command.bigDecimalValueOfParameterNamed(LoanProductConstants.DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT);
actualChanges.put(LoanProductConstants.DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT, newValue);
loanProduct.getLoanProductRelatedDetail().setDisbursedAmountPercentageForDownPayment(newValue);
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT,
loanProduct.getLoanProductRelatedDetail().isEnableAutoRepaymentForDownPayment())) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT);
actualChanges.put(LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT, newValue);
loanProduct.getLoanProductRelatedDetail().setEnableAutoRepaymentForDownPayment(newValue);
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.REPAYMENT_START_DATE_TYPE,
loanProduct.getRepaymentStartDateType().getValue())) {
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.REPAYMENT_START_DATE_TYPE);
actualChanges.put(LoanProductConstants.REPAYMENT_START_DATE_TYPE, newValue);
loanProduct.setRepaymentStartDateType(RepaymentStartDateType.fromInt(newValue));
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY,
loanProduct.isEnableInstallmentLevelDelinquency())) {
final boolean newValue = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY);
actualChanges.put(LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY, newValue);
loanProduct.updateEnableInstallmentLevelDelinquency(newValue);
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.FIXED_LENGTH,
loanProduct.getLoanProductRelatedDetail().getFixedLength())) {
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.FIXED_LENGTH);
actualChanges.put(LoanProductConstants.FIXED_LENGTH, newValue);
loanProduct.getLoanProductRelatedDetail().setFixedLength(newValue);
}
return actualChanges;
}
private Map<String, Object> updateBorrowerCycleVariations(final LoanProduct loanProduct, final JsonCommand command) {
final Map<String, Object> actualChanges = new LinkedHashMap<>(20);
List<Long> variationIds = fetchAllVariationIds(loanProduct);
updateBorrowerCycleVariations(loanProduct, command, LoanProductParamType.PRINCIPAL.getValue(),
LoanProductConstants.PRINCIPAL_VARIATIONS_FOR_BORROWER_CYCLE_PARAMETER_NAME, actualChanges, variationIds);
updateBorrowerCycleVariations(loanProduct, command, LoanProductParamType.INTERESTRATE.getValue(),
LoanProductConstants.INTEREST_RATE_VARIATIONS_FOR_BORROWER_CYCLE_PARAMETER_NAME, actualChanges, variationIds);
updateBorrowerCycleVariations(loanProduct, command, LoanProductParamType.REPAYMENT.getValue(),
LoanProductConstants.NUMBER_OF_REPAYMENT_VARIATIONS_FOR_BORROWER_CYCLE_PARAMETER_NAME, actualChanges, variationIds);
for (Long id : variationIds) {
loanProduct.getBorrowerCycleVariations().remove(fetchLoanProductBorrowerCycleVariationById(loanProduct, id));
}
return actualChanges;
}
public LoanProductBorrowerCycleVariations fetchLoanProductBorrowerCycleVariationById(LoanProduct loanProduct, Long id) {
LoanProductBorrowerCycleVariations borrowerCycleVariation = null;
for (LoanProductBorrowerCycleVariations cycleVariation : loanProduct.getBorrowerCycleVariations()) {
if (id.equals(cycleVariation.getId())) {
borrowerCycleVariation = cycleVariation;
break;
}
}
return borrowerCycleVariation;
}
private List<Long> fetchAllVariationIds(LoanProduct loanProduct) {
List<Long> list = new ArrayList<>();
for (LoanProductBorrowerCycleVariations cycleVariation : loanProduct.getBorrowerCycleVariations()) {
list.add(cycleVariation.getId());
}
return list;
}
private void updateBorrowerCycleVariations(final LoanProduct loanProduct, 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(loanProduct);
loanProduct.getBorrowerCycleVariations().add(borrowerCycleVariations);
actualChanges.put("borrowerCycleParamType", paramType);
} else {
variationIds.remove(id);
LoanProductBorrowerCycleVariations existingCycleVariation = fetchLoanProductBorrowerCycleVariationById(loanProduct,
id);
if (!existingCycleVariation.equals(borrowerCycleVariations)) {
existingCycleVariation.copy(borrowerCycleVariations);
actualChanges.put("borrowerCycleId", id);
}
}
i++;
} while (i < variationArray.size());
}
}
}
private void clearVariations(LoanProduct loanProduct) {
loanProduct.getBorrowerCycleVariations().clear();
}
}
@@ -0,0 +1,52 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.loanaccount.service;
import java.util.LinkedHashMap;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductVariableInstallmentConfig;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class LoanProductVariableInstallmentConfigUpdateUtil {
public Map<? extends String, ?> update(LoanProductVariableInstallmentConfig loanProductVariableInstallmentConfig, JsonCommand command) {
final Map<String, Object> actualChanges = new LinkedHashMap<>(3);
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.minimumGapBetweenInstallments,
loanProductVariableInstallmentConfig.getMinimumGap())) {
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.minimumGapBetweenInstallments);
actualChanges.put(LoanProductConstants.minimumGapBetweenInstallments, newValue);
loanProductVariableInstallmentConfig.setMinimumGap(newValue);
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.maximumGapBetweenInstallments,
loanProductVariableInstallmentConfig.getMaximumGap())) {
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.maximumGapBetweenInstallments);
actualChanges.put(LoanProductConstants.maximumGapBetweenInstallments, newValue);
loanProductVariableInstallmentConfig.setMaximumGap(newValue);
}
return actualChanges;
}
}
@@ -55,6 +55,8 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeOffBehaviour;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.AprCalculator;
import org.apache.fineract.portfolio.loanaccount.service.LoanProductAssembler;
import org.apache.fineract.portfolio.loanaccount.service.LoanProductUpdateUtil;
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
import org.apache.fineract.portfolio.loanproduct.domain.AdvancedPaymentAllocationsJsonParser;
import org.apache.fineract.portfolio.loanproduct.domain.CreditAllocationsJsonParser;
@@ -93,6 +95,8 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
private final AdvancedPaymentAllocationsJsonParser advancedPaymentJsonParser;
private final CreditAllocationsJsonParser creditAllocationsJsonParser;
private final LoanProductAssembler loanProductAssembler;
private final LoanProductUpdateUtil loanProductUpdateUtil;
private final LoanProductPaymentAllocationRuleMerger loanProductPaymentAllocationRuleMerger = new LoanProductPaymentAllocationRuleMerger();
private final LoanProductCreditAllocationRuleMerger loanProductCreditAllocationRuleMerger = new LoanProductCreditAllocationRuleMerger();
@@ -123,8 +127,8 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
floatingRate = this.floatingRateRepository
.findOneWithNotFoundDetection(command.longValueOfParameterNamed("floatingRatesId"));
}
final LoanProduct loanProduct = LoanProduct.assembleFromJson(fund, loanTransactionProcessingStrategyCode, charges, command,
this.aprCalculator, floatingRate, rates, loanProductPaymentAllocationRules, loanProductCreditAllocationRules);
final LoanProduct loanProduct = loanProductAssembler.assembleFromJson(fund, loanTransactionProcessingStrategyCode, charges,
command, this.aprCalculator, floatingRate, rates, loanProductPaymentAllocationRules, loanProductCreditAllocationRules);
loanProduct.updateLoanProductInRelatedClasses();
loanProduct.setTransactionProcessingStrategyName(
@@ -204,7 +208,7 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
.findOneWithNotFoundDetection(command.longValueOfParameterNamed("floatingRatesId"));
}
final Map<String, Object> changes = product.update(command, this.aprCalculator, floatingRate);
final Map<String, Object> changes = loanProductUpdateUtil.update(product, command, this.aprCalculator, floatingRate);
if (changes.containsKey("fundId")) {
final Long fundId = (Long) changes.get("fundId");
@@ -32,6 +32,8 @@ import org.apache.fineract.portfolio.fund.domain.FundRepository;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.AprCalculator;
import org.apache.fineract.portfolio.loanaccount.service.LoanProductAssembler;
import org.apache.fineract.portfolio.loanaccount.service.LoanProductUpdateUtil;
import org.apache.fineract.portfolio.loanproduct.domain.AdvancedPaymentAllocationsJsonParser;
import org.apache.fineract.portfolio.loanproduct.domain.CreditAllocationsJsonParser;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
@@ -79,10 +81,12 @@ public class LoanProductConfiguration {
LoanRepositoryWrapper loanRepositoryWrapper, BusinessEventNotifierService businessEventNotifierService,
DelinquencyBucketRepository delinquencyBucketRepository,
LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
AdvancedPaymentAllocationsJsonParser advancedPaymentJsonParser, CreditAllocationsJsonParser creditAllocationsJsonParser) {
AdvancedPaymentAllocationsJsonParser advancedPaymentJsonParser, CreditAllocationsJsonParser creditAllocationsJsonParser,
LoanProductAssembler loanProductAssembler, LoanProductUpdateUtil loanProductUpdateUtil) {
return new LoanProductWritePlatformServiceJpaRepositoryImpl(context, fromApiJsonDeserializer, loanProductRepository, aprCalculator,
fundRepository, chargeRepository, rateRepository, accountMappingWritePlatformService, fineractEntityAccessUtil,
floatingRateRepository, loanRepositoryWrapper, businessEventNotifierService, delinquencyBucketRepository,
loanRepaymentScheduleTransactionProcessorFactory, advancedPaymentJsonParser, creditAllocationsJsonParser);
loanRepaymentScheduleTransactionProcessorFactory, advancedPaymentJsonParser, creditAllocationsJsonParser,
loanProductAssembler, loanProductUpdateUtil);
}
}