From f8d5bde92177bce7c5a0ea7acad3f58bd93ec93e Mon Sep 17 00:00:00 2001 From: "mark.vituska" Date: Wed, 9 Apr 2025 16:00:05 +0200 Subject: [PATCH] FINERACT-2080: extracted json based workflows from Loan and other Loan related entities --- .../portfolio/loanaccount/domain/Loan.java | 2 +- .../LoanInterestRecalculationDetails.java | 4 +- .../loanproduct/domain/LoanProduct.java | 897 +----------------- .../domain/LoanProductFloatingRates.java | 81 +- .../domain/LoanProductGuaranteeDetails.java | 57 +- ...anProductInterestRecalculationDetails.java | 346 +------ .../domain/LoanProductRelatedDetail.java | 258 ----- .../domain/LoanProductTrancheDetails.java | 46 +- .../LoanProductVariableInstallmentConfig.java | 23 +- .../service/LoanScheduleAssembler.java | 8 +- .../service/LoanProductAssembler.java | 406 ++++++++ .../LoanProductFloatingRatesUpdateUtil.java | 84 ++ .../LoanProductGuaranteeDetailsAssembler.java | 42 + ...LoanProductGuaranteeDetailsUpdateUtil.java | 59 ++ ...InterestRecalculationDetailsAssembler.java | 105 ++ ...nterestRecalculationDetailsUpdateUtil.java | 247 +++++ ...oanProductMinMaxConstraintsUpdateUtil.java | 95 ++ .../LoanProductRelatedDetailUpdateUtil.java | 309 ++++++ .../LoanProductTrancheDetailsUpdateUtil.java | 62 ++ .../service/LoanProductUpdateUtil.java | 632 ++++++++++++ ...ctVariableInstallmentConfigUpdateUtil.java | 52 + ...WritePlatformServiceJpaRepositoryImpl.java | 10 +- .../starter/LoanProductConfiguration.java | 8 +- 23 files changed, 2136 insertions(+), 1697 deletions(-) create mode 100644 fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductAssembler.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductFloatingRatesUpdateUtil.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductGuaranteeDetailsAssembler.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductGuaranteeDetailsUpdateUtil.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductInterestRecalculationDetailsAssembler.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductInterestRecalculationDetailsUpdateUtil.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductMinMaxConstraintsUpdateUtil.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductRelatedDetailUpdateUtil.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductTrancheDetailsUpdateUtil.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductUpdateUtil.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductVariableInstallmentConfigUpdateUtil.java diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java index 6110ced7a..41704d4dc 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java @@ -1233,7 +1233,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { || 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; } diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanInterestRecalculationDetails.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanInterestRecalculationDetails.java index 20eb8d6e3..0c54b9ec3 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanInterestRecalculationDetails.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanInterestRecalculationDetails.java @@ -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()); } diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java index c010ae42b..c9b85ac25 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java @@ -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 { @Column(name = "repayment_start_date_type_enum", nullable = false) private RepaymentStartDateType repaymentStartDateType; - public static LoanProduct assembleFromJson(final Fund fund, final String loanTransactionProcessingStrategy, - final List productCharges, final JsonCommand command, final AprCalculator aprCalculator, FloatingRate floatingRate, - final List productRates, List loanProductPaymentAllocationRules, - List 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 = 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 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 { } } - private static void populateBorrowerCycleVariations(final JsonCommand command, - final Set loanProductBorrowerCycleVariations) { - assemblePrincipalVariations(command, loanProductBorrowerCycleVariations); - - assembleRepaymentVariations(command, loanProductBorrowerCycleVariations); - - assembleInterestRateVariations(command, loanProductBorrowerCycleVariations); - } - - private static void assembleInterestRateVariations(final JsonCommand command, - final Set 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) { - 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) { - assembleVariations(command, loanProductBorrowerCycleVariations, LoanProductParamType.PRINCIPAL.getValue(), - LoanProductConstants.PRINCIPAL_VARIATIONS_FOR_BORROWER_CYCLE_PARAMETER_NAME); - } - - private static void assembleVariations(final JsonCommand command, - final Set 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 updateBorrowerCycleVariations(final JsonCommand command) { - final Map actualChanges = new LinkedHashMap<>(20); - List 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 fetchAllVariationIds() { - List 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 actualChanges, List 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 { return updated; } - public Map update(final JsonCommand command, final AprCalculator aprCalculator, FloatingRate floatingRate) { - - final Map 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 { } 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 { 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 fetchBorrowerCycleVariationsForCycleNumber(final Integer cycleNumber) { Map borrowerCycleVariations = new HashMap<>(); borrowerCycleVariations.put(LoanProductConstants.PRINCIPAL, this.loanProductRelatedDetail.getPrincipal().getAmount()); diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductFloatingRates.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductFloatingRates.java index 6ab89e8d8..db544d87d 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductFloatingRates.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductFloatingRates.java @@ -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 { @@ -77,80 +78,6 @@ public class LoanProductFloatingRates extends AbstractPersistableCustom { 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 update(JsonCommand command, FloatingRate floatingRate) { - final Map 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 fetchInterestRates(final FloatingRateDTO floatingRateDTO) { floatingRateDTO.addInterestRateDiff(this.interestRateDifferential); return floatingRate.fetchInterestRates(floatingRateDTO); diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductGuaranteeDetails.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductGuaranteeDetails.java index 5855dc15a..cd8df055e 100755 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductGuaranteeDetails.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductGuaranteeDetails.java @@ -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 { @@ -56,18 +57,7 @@ public class LoanProductGuaranteeDetails extends AbstractPersistableCustom // } - 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 this.loanProduct = loanProduct; } - public void update(final JsonCommand command, final Map 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; - } - } diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductInterestRecalculationDetails.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductInterestRecalculationDetails.java index e9bc005f9..1bc08ad40 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductInterestRecalculationDetails.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductInterestRecalculationDetails.java @@ -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 { @@ -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 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; - } } diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRelatedDetail.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRelatedDetail.java index 8f8574a33..a1a68ae21 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRelatedDetail.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRelatedDetail.java @@ -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 update(final JsonCommand command, final AprCalculator aprCalculator) { - - final Map 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); } diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductTrancheDetails.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductTrancheDetails.java index 22bb32e45..2a7142adc 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductTrancheDetails.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductTrancheDetails.java @@ -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 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; - } - } diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductVariableInstallmentConfig.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductVariableInstallmentConfig.java index 53922b3c9..d2accf793 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductVariableInstallmentConfig.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductVariableInstallmentConfig.java @@ -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 update(JsonCommand command) { - final Map 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; - } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java index 802989844..f6fb5578f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java @@ -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"; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductAssembler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductAssembler.java new file mode 100644 index 000000000..67b748065 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductAssembler.java @@ -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 productCharges, + final JsonCommand command, final AprCalculator aprCalculator, FloatingRate floatingRate, final List productRates, + List loanProductPaymentAllocationRules, + List 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 = 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 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) { + assemblePrincipalVariations(command, loanProductBorrowerCycleVariations); + + assembleRepaymentVariations(command, loanProductBorrowerCycleVariations); + + assembleInterestRateVariations(command, loanProductBorrowerCycleVariations); + } + + private void assembleInterestRateVariations(final JsonCommand command, + final Set 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) { + 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) { + assembleVariations(command, loanProductBorrowerCycleVariations, LoanProductParamType.PRINCIPAL.getValue(), + LoanProductConstants.PRINCIPAL_VARIATIONS_FOR_BORROWER_CYCLE_PARAMETER_NAME); + } + + private void assembleVariations(final JsonCommand command, + final Set 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()); + } + } + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductFloatingRatesUpdateUtil.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductFloatingRatesUpdateUtil.java new file mode 100644 index 000000000..7a62bbc6b --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductFloatingRatesUpdateUtil.java @@ -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 update(LoanProductFloatingRates loanProductFloatingRates, JsonCommand command, + FloatingRate floatingRate) { + final Map 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; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductGuaranteeDetailsAssembler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductGuaranteeDetailsAssembler.java new file mode 100644 index 000000000..6a61f95d1 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductGuaranteeDetailsAssembler.java @@ -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); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductGuaranteeDetailsUpdateUtil.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductGuaranteeDetailsUpdateUtil.java new file mode 100644 index 000000000..1b0a57ef9 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductGuaranteeDetailsUpdateUtil.java @@ -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 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); + } + + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductInterestRecalculationDetailsAssembler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductInterestRecalculationDetailsAssembler.java new file mode 100644 index 000000000..732cedb4c --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductInterestRecalculationDetailsAssembler.java @@ -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); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductInterestRecalculationDetailsUpdateUtil.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductInterestRecalculationDetailsUpdateUtil.java new file mode 100644 index 000000000..c02594d79 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductInterestRecalculationDetailsUpdateUtil.java @@ -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 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); + } + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductMinMaxConstraintsUpdateUtil.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductMinMaxConstraintsUpdateUtil.java new file mode 100644 index 000000000..08202d503 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductMinMaxConstraintsUpdateUtil.java @@ -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 update(final LoanProductMinMaxConstraints loanProductMinMaxConstraints, final JsonCommand command) { + + final Map 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; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductRelatedDetailUpdateUtil.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductRelatedDetailUpdateUtil.java new file mode 100644 index 000000000..9e286fe24 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductRelatedDetailUpdateUtil.java @@ -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 updateLoanRepaymentSchedule(final LoanProductRelatedDetail loanRepaymentScheduleDetail, + final JsonCommand command, final AprCalculator aprCalculator) { + + final Map 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); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductTrancheDetailsUpdateUtil.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductTrancheDetailsUpdateUtil.java new file mode 100644 index 000000000..045097cc2 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductTrancheDetailsUpdateUtil.java @@ -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 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); + } + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductUpdateUtil.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductUpdateUtil.java new file mode 100644 index 000000000..af8d77cc3 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductUpdateUtil.java @@ -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 update(final LoanProduct loanProduct, final JsonCommand command, final AprCalculator aprCalculator, + FloatingRate floatingRate) { + final Map 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 updateBorrowerCycleVariations(final LoanProduct loanProduct, final JsonCommand command) { + final Map actualChanges = new LinkedHashMap<>(20); + List 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 fetchAllVariationIds(LoanProduct loanProduct) { + List 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 actualChanges, List 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(); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductVariableInstallmentConfigUpdateUtil.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductVariableInstallmentConfigUpdateUtil.java new file mode 100644 index 000000000..6744a6c8e --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductVariableInstallmentConfigUpdateUtil.java @@ -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 update(LoanProductVariableInstallmentConfig loanProductVariableInstallmentConfig, JsonCommand command) { + final Map 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; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java index 2f25dfb74..5845488f3 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java @@ -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 changes = product.update(command, this.aprCalculator, floatingRate); + final Map changes = loanProductUpdateUtil.update(product, command, this.aprCalculator, floatingRate); if (changes.containsKey("fundId")) { final Long fundId = (Long) changes.get("fundId"); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/starter/LoanProductConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/starter/LoanProductConfiguration.java index e5349dc65..e5617d0c1 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/starter/LoanProductConfiguration.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/starter/LoanProductConfiguration.java @@ -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); } }