in fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java [216:891]
public void validateForCreate(final JsonCommand command) {
String json = command.json();
if (StringUtils.isBlank(json)) {
throw new InvalidJsonException();
}
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, SUPPORTED_PARAMETERS);
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(LOANPRODUCT);
final JsonElement element = this.fromApiJsonHelper.parse(json);
final String name = this.fromApiJsonHelper.extractStringNamed(NAME, element);
baseDataValidator.reset().parameter(NAME).value(name).notBlank().notExceedingLengthOf(100);
final String shortName = this.fromApiJsonHelper.extractStringNamed(LoanProductConstants.SHORT_NAME, element);
baseDataValidator.reset().parameter(LoanProductConstants.SHORT_NAME).value(shortName).notBlank().notExceedingLengthOf(4);
final String description = this.fromApiJsonHelper.extractStringNamed(DESCRIPTION, element);
baseDataValidator.reset().parameter(DESCRIPTION).value(description).notExceedingLengthOf(500);
if (this.fromApiJsonHelper.parameterExists(FUND_ID, element)) {
final Long fundId = this.fromApiJsonHelper.extractLongNamed(FUND_ID, element);
baseDataValidator.reset().parameter(FUND_ID).value(fundId).ignoreIfNull().integerGreaterThanZero();
}
boolean isEqualAmortization = false;
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM, element)) {
isEqualAmortization = this.fromApiJsonHelper.extractBooleanNamed(LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM, element);
baseDataValidator.reset().parameter(LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM).value(isEqualAmortization).ignoreIfNull()
.validateForBooleanValue();
}
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.MINIMUM_DAYS_BETWEEN_DISBURSAL_AND_FIRST_REPAYMENT, element)) {
final Long minimumDaysBetweenDisbursalAndFirstRepayment = this.fromApiJsonHelper
.extractLongNamed(LoanProductConstants.MINIMUM_DAYS_BETWEEN_DISBURSAL_AND_FIRST_REPAYMENT, element);
baseDataValidator.reset().parameter(LoanProductConstants.MINIMUM_DAYS_BETWEEN_DISBURSAL_AND_FIRST_REPAYMENT)
.value(minimumDaysBetweenDisbursalAndFirstRepayment).ignoreIfNull().integerGreaterThanZero();
}
final Boolean includeInBorrowerCycle = this.fromApiJsonHelper.extractBooleanNamed(INCLUDE_IN_BORROWER_CYCLE, element);
baseDataValidator.reset().parameter(INCLUDE_IN_BORROWER_CYCLE).value(includeInBorrowerCycle).ignoreIfNull()
.validateForBooleanValue();
// terms
final String currencyCode = this.fromApiJsonHelper.extractStringNamed(CURRENCY_CODE, element);
baseDataValidator.reset().parameter(CURRENCY_CODE).value(currencyCode).notBlank().notExceedingLengthOf(3);
final Integer digitsAfterDecimal = this.fromApiJsonHelper.extractIntegerNamed(DIGITS_AFTER_DECIMAL, element, Locale.getDefault());
baseDataValidator.reset().parameter(DIGITS_AFTER_DECIMAL).value(digitsAfterDecimal).notNull().inMinMaxRange(0, 6);
final Integer inMultiplesOf = this.fromApiJsonHelper.extractIntegerNamed(IN_MULTIPLES_OF, element, Locale.getDefault());
baseDataValidator.reset().parameter(IN_MULTIPLES_OF).value(inMultiplesOf).ignoreIfNull().integerZeroOrGreater();
final BigDecimal principal = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(PRINCIPAL, element);
baseDataValidator.reset().parameter(PRINCIPAL).value(principal).positiveAmount();
final String minPrincipalParameterName = MIN_PRINCIPAL;
BigDecimal minPrincipalAmount = null;
if (this.fromApiJsonHelper.parameterExists(minPrincipalParameterName, element)) {
minPrincipalAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minPrincipalParameterName, element);
baseDataValidator.reset().parameter(minPrincipalParameterName).value(minPrincipalAmount).ignoreIfNull().positiveAmount();
}
final String maxPrincipalParameterName = MAX_PRINCIPAL;
BigDecimal maxPrincipalAmount = null;
if (this.fromApiJsonHelper.parameterExists(maxPrincipalParameterName, element)) {
maxPrincipalAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(maxPrincipalParameterName, element);
baseDataValidator.reset().parameter(maxPrincipalParameterName).value(maxPrincipalAmount).ignoreIfNull().positiveAmount();
}
if (maxPrincipalAmount != null && maxPrincipalAmount.compareTo(BigDecimal.ZERO) >= 0) {
if (minPrincipalAmount != null && minPrincipalAmount.compareTo(BigDecimal.ZERO) >= 0) {
baseDataValidator.reset().parameter(maxPrincipalParameterName).value(maxPrincipalAmount).notLessThanMin(minPrincipalAmount);
if (minPrincipalAmount.compareTo(maxPrincipalAmount) <= 0 && principal != null) {
baseDataValidator.reset().parameter(PRINCIPAL).value(principal).inMinAndMaxAmountRange(minPrincipalAmount,
maxPrincipalAmount);
}
} else if (principal != null) {
baseDataValidator.reset().parameter(PRINCIPAL).value(principal).notGreaterThanMax(maxPrincipalAmount);
}
} else if (minPrincipalAmount != null && minPrincipalAmount.compareTo(BigDecimal.ZERO) >= 0 && principal != null) {
baseDataValidator.reset().parameter(PRINCIPAL).value(principal).notLessThanMin(minPrincipalAmount);
}
final Integer numberOfRepayments = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(NUMBER_OF_REPAYMENTS, element);
baseDataValidator.reset().parameter(NUMBER_OF_REPAYMENTS).value(numberOfRepayments).notNull().integerGreaterThanZero();
final String minNumberOfRepaymentsParameterName = MIN_NUMBER_OF_REPAYMENTS;
Integer minNumberOfRepayments = null;
if (this.fromApiJsonHelper.parameterExists(minNumberOfRepaymentsParameterName, element)) {
minNumberOfRepayments = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(minNumberOfRepaymentsParameterName, element);
baseDataValidator.reset().parameter(minNumberOfRepaymentsParameterName).value(minNumberOfRepayments).ignoreIfNull()
.integerGreaterThanZero();
}
final String maxNumberOfRepaymentsParameterName = MAX_NUMBER_OF_REPAYMENTS;
Integer maxNumberOfRepayments = null;
if (this.fromApiJsonHelper.parameterExists(maxNumberOfRepaymentsParameterName, element)) {
maxNumberOfRepayments = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(maxNumberOfRepaymentsParameterName, element);
baseDataValidator.reset().parameter(maxNumberOfRepaymentsParameterName).value(maxNumberOfRepayments).ignoreIfNull()
.integerGreaterThanZero();
}
if (maxNumberOfRepayments != null && maxNumberOfRepayments.compareTo(0) > 0) {
if (minNumberOfRepayments != null && minNumberOfRepayments.compareTo(0) > 0) {
baseDataValidator.reset().parameter(maxNumberOfRepaymentsParameterName).value(maxNumberOfRepayments)
.notLessThanMin(minNumberOfRepayments);
if (minNumberOfRepayments.compareTo(maxNumberOfRepayments) <= 0) {
baseDataValidator.reset().parameter(NUMBER_OF_REPAYMENTS).value(numberOfRepayments).inMinMaxRange(minNumberOfRepayments,
maxNumberOfRepayments);
}
} else {
baseDataValidator.reset().parameter(NUMBER_OF_REPAYMENTS).value(numberOfRepayments)
.notGreaterThanMax(maxNumberOfRepayments);
}
} else if (minNumberOfRepayments != null && minNumberOfRepayments.compareTo(0) > 0) {
baseDataValidator.reset().parameter(NUMBER_OF_REPAYMENTS).value(numberOfRepayments).notLessThanMin(minNumberOfRepayments);
}
final Integer repaymentEvery = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(REPAYMENT_EVERY, element);
baseDataValidator.reset().parameter(REPAYMENT_EVERY).value(repaymentEvery).notNull().integerGreaterThanZero();
final Integer repaymentFrequencyType = this.fromApiJsonHelper.extractIntegerNamed(REPAYMENT_FREQUENCY_TYPE, element,
Locale.getDefault());
baseDataValidator.reset().parameter(REPAYMENT_FREQUENCY_TYPE).value(repaymentFrequencyType).notNull().inMinMaxRange(0, 3);
// settings
final Integer amortizationType = this.fromApiJsonHelper.extractIntegerNamed(AMORTIZATION_TYPE, element, Locale.getDefault());
baseDataValidator.reset().parameter(AMORTIZATION_TYPE).value(amortizationType).notNull().inMinMaxRange(0, 1);
final Integer interestType = this.fromApiJsonHelper.extractIntegerNamed(INTEREST_TYPE, element, Locale.getDefault());
baseDataValidator.reset().parameter(INTEREST_TYPE).value(interestType).notNull().inMinMaxRange(0, 1);
final Integer interestCalculationPeriodType = this.fromApiJsonHelper.extractIntegerNamed(INTEREST_CALCULATION_PERIOD_TYPE, element,
Locale.getDefault());
baseDataValidator.reset().parameter(INTEREST_CALCULATION_PERIOD_TYPE).value(interestCalculationPeriodType).notNull()
.inMinMaxRange(0, 1);
final BigDecimal inArrearsTolerance = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(IN_ARREARS_TOLERANCE, element);
baseDataValidator.reset().parameter(IN_ARREARS_TOLERANCE).value(inArrearsTolerance).ignoreIfNull().zeroOrPositiveAmount();
final String transactionProcessingStrategyCode = this.fromApiJsonHelper.extractStringNamed(TRANSACTION_PROCESSING_STRATEGY_CODE,
element);
baseDataValidator.reset().parameter(TRANSACTION_PROCESSING_STRATEGY_CODE).value(transactionProcessingStrategyCode).notBlank();
// Validating whether the processor is existing
loanRepaymentScheduleTransactionProcessorFactory.determineProcessor(transactionProcessingStrategyCode);
Long delinquencyBucketId = null;
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME, element)) {
delinquencyBucketId = this.fromApiJsonHelper.extractLongNamed(LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME, element);
baseDataValidator.reset().parameter(LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME).value(delinquencyBucketId)
.ignoreIfNull().integerGreaterThanZero();
}
// grace validation
final Integer graceOnPrincipalPayment = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(GRACE_ON_PRINCIPAL_PAYMENT, element);
baseDataValidator.reset().parameter(GRACE_ON_PRINCIPAL_PAYMENT).value(graceOnPrincipalPayment).zeroOrPositiveAmount();
final Integer graceOnInterestPayment = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(GRACE_ON_INTEREST_PAYMENT, element);
baseDataValidator.reset().parameter(GRACE_ON_INTEREST_PAYMENT).value(graceOnInterestPayment).zeroOrPositiveAmount();
final Integer graceOnInterestCharged = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(GRACE_ON_INTEREST_CHARGED, element);
baseDataValidator.reset().parameter(GRACE_ON_INTEREST_CHARGED).value(graceOnInterestCharged).zeroOrPositiveAmount();
final Integer graceOnArrearsAgeing = this.fromApiJsonHelper
.extractIntegerWithLocaleNamed(LoanProductConstants.GRACE_ON_ARREARS_AGEING_PARAMETER_NAME, element);
baseDataValidator.reset().parameter(LoanProductConstants.GRACE_ON_ARREARS_AGEING_PARAMETER_NAME).value(graceOnArrearsAgeing)
.integerZeroOrGreater();
final Integer overdueDaysForNPA = this.fromApiJsonHelper
.extractIntegerWithLocaleNamed(LoanProductConstants.OVERDUE_DAYS_FOR_NPA_PARAMETER_NAME, element);
baseDataValidator.reset().parameter(LoanProductConstants.OVERDUE_DAYS_FOR_NPA_PARAMETER_NAME).value(overdueDaysForNPA)
.integerZeroOrGreater();
final Integer daysInYearType = this.fromApiJsonHelper.extractIntegerNamed(LoanProductConstants.DAYS_IN_YEAR_TYPE_PARAMETER_NAME,
element, Locale.getDefault());
baseDataValidator.reset().parameter(LoanProductConstants.DAYS_IN_YEAR_TYPE_PARAMETER_NAME).value(daysInYearType).notNull()
.isOneOfTheseValues(1, 360, 364, 365);
final Integer daysInMonthType = this.fromApiJsonHelper.extractIntegerNamed(LoanProductConstants.DAYS_IN_MONTH_TYPE_PARAMETER_NAME,
element, Locale.getDefault());
baseDataValidator.reset().parameter(LoanProductConstants.DAYS_IN_MONTH_TYPE_PARAMETER_NAME).value(daysInMonthType).notNull()
.isOneOfTheseValues(1, 30);
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.ACCOUNT_MOVES_OUT_OF_NPA_ONLY_ON_ARREARS_COMPLETION_PARAM_NAME,
element)) {
Boolean npaChangeConfig = this.fromApiJsonHelper
.extractBooleanNamed(LoanProductConstants.ACCOUNT_MOVES_OUT_OF_NPA_ONLY_ON_ARREARS_COMPLETION_PARAM_NAME, element);
baseDataValidator.reset().parameter(LoanProductConstants.ACCOUNT_MOVES_OUT_OF_NPA_ONLY_ON_ARREARS_COMPLETION_PARAM_NAME)
.value(npaChangeConfig).notNull().isOneOfTheseValues(true, false);
}
// Interest recalculation settings
final Boolean isInterestRecalculationEnabled = this.fromApiJsonHelper
.extractBooleanNamed(LoanProductConstants.IS_INTEREST_RECALCULATION_ENABLED_PARAMETER_NAME, element);
baseDataValidator.reset().parameter(LoanProductConstants.IS_INTEREST_RECALCULATION_ENABLED_PARAMETER_NAME)
.value(isInterestRecalculationEnabled).notNull().isOneOfTheseValues(true, false);
if (isInterestRecalculationEnabled != null && isInterestRecalculationEnabled) {
if (isEqualAmortization) {
throw new EqualAmortizationUnsupportedFeatureException("interest.recalculation", "interest recalculation");
}
validateInterestRecalculationParams(element, baseDataValidator, null);
}
// interest rates
boolean isInterestBearing = false;
if (this.fromApiJsonHelper.parameterExists(IS_LINKED_TO_FLOATING_INTEREST_RATES, element)
&& this.fromApiJsonHelper.extractBooleanNamed(IS_LINKED_TO_FLOATING_INTEREST_RATES, element)) {
if (isEqualAmortization) {
throw new EqualAmortizationUnsupportedFeatureException("floating.interest.rate", "floating interest rate");
}
if (this.fromApiJsonHelper.parameterExists(INTEREST_RATE_PER_PERIOD, element)) {
baseDataValidator.reset().parameter(INTEREST_RATE_PER_PERIOD).failWithCode(
"not.supported.when.isLinkedToFloatingInterestRates.is.true",
"interestRatePerPeriod param is not supported when isLinkedToFloatingInterestRates is true");
}
if (this.fromApiJsonHelper.parameterExists(MIN_INTEREST_RATE_PER_PERIOD, element)) {
baseDataValidator.reset().parameter(MIN_INTEREST_RATE_PER_PERIOD).failWithCode(
"not.supported.when.isLinkedToFloatingInterestRates.is.true",
"minInterestRatePerPeriod param is not supported when isLinkedToFloatingInterestRates is true");
}
if (this.fromApiJsonHelper.parameterExists(MAX_INTEREST_RATE_PER_PERIOD, element)) {
baseDataValidator.reset().parameter(MAX_INTEREST_RATE_PER_PERIOD).failWithCode(
"not.supported.when.isLinkedToFloatingInterestRates.is.true",
"maxInterestRatePerPeriod param is not supported when isLinkedToFloatingInterestRates is true");
}
if (this.fromApiJsonHelper.parameterExists(INTEREST_RATE_FREQUENCY_TYPE, element)) {
baseDataValidator.reset().parameter(INTEREST_RATE_FREQUENCY_TYPE).failWithCode(
"not.supported.when.isLinkedToFloatingInterestRates.is.true",
"interestRateFrequencyType param is not supported when isLinkedToFloatingInterestRates is true");
}
if ((interestType == null || !interestType.equals(InterestMethod.DECLINING_BALANCE.getValue()))
|| (isInterestRecalculationEnabled == null || !isInterestRecalculationEnabled)) {
baseDataValidator.reset().parameter(IS_LINKED_TO_FLOATING_INTEREST_RATES).failWithCode(
"supported.only.for.declining.balance.interest.recalculation.enabled",
"Floating interest rates are supported only for declining balance and interest recalculation enabled loan products");
}
final Integer floatingRatesId = this.fromApiJsonHelper.extractIntegerNamed(FLOATING_RATES_ID, element, Locale.getDefault());
baseDataValidator.reset().parameter(FLOATING_RATES_ID).value(floatingRatesId).notNull();
final BigDecimal interestRateDifferential = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(INTEREST_RATE_DIFFERENTIAL,
element);
baseDataValidator.reset().parameter(INTEREST_RATE_DIFFERENTIAL).value(interestRateDifferential).notNull()
.zeroOrPositiveAmount();
final String minDifferentialLendingRateParameterName = MIN_DIFFERENTIAL_LENDING_RATE;
BigDecimal minDifferentialLendingRate = this.fromApiJsonHelper
.extractBigDecimalWithLocaleNamed(minDifferentialLendingRateParameterName, element);
baseDataValidator.reset().parameter(minDifferentialLendingRateParameterName).value(minDifferentialLendingRate).notNull()
.zeroOrPositiveAmount();
final String defaultDifferentialLendingRateParameterName = DEFAULT_DIFFERENTIAL_LENDING_RATE;
BigDecimal defaultDifferentialLendingRate = this.fromApiJsonHelper
.extractBigDecimalWithLocaleNamed(defaultDifferentialLendingRateParameterName, element);
baseDataValidator.reset().parameter(defaultDifferentialLendingRateParameterName).value(defaultDifferentialLendingRate).notNull()
.zeroOrPositiveAmount();
final String maxDifferentialLendingRateParameterName = MAX_DIFFERENTIAL_LENDING_RATE;
BigDecimal maxDifferentialLendingRate = this.fromApiJsonHelper
.extractBigDecimalWithLocaleNamed(maxDifferentialLendingRateParameterName, element);
baseDataValidator.reset().parameter(maxDifferentialLendingRateParameterName).value(maxDifferentialLendingRate).notNull()
.zeroOrPositiveAmount();
if (defaultDifferentialLendingRate != null && defaultDifferentialLendingRate.compareTo(BigDecimal.ZERO) >= 0
&& minDifferentialLendingRate != null && minDifferentialLendingRate.compareTo(BigDecimal.ZERO) >= 0) {
baseDataValidator.reset().parameter(DEFAULT_DIFFERENTIAL_LENDING_RATE).value(defaultDifferentialLendingRate)
.notLessThanMin(minDifferentialLendingRate);
}
if (maxDifferentialLendingRate != null && maxDifferentialLendingRate.compareTo(BigDecimal.ZERO) >= 0
&& minDifferentialLendingRate != null && minDifferentialLendingRate.compareTo(BigDecimal.ZERO) >= 0) {
baseDataValidator.reset().parameter(MAX_DIFFERENTIAL_LENDING_RATE).value(maxDifferentialLendingRate)
.notLessThanMin(minDifferentialLendingRate);
}
if (maxDifferentialLendingRate != null && maxDifferentialLendingRate.compareTo(BigDecimal.ZERO) >= 0
&& defaultDifferentialLendingRate != null && defaultDifferentialLendingRate.compareTo(BigDecimal.ZERO) >= 0) {
baseDataValidator.reset().parameter(MAX_DIFFERENTIAL_LENDING_RATE).value(maxDifferentialLendingRate)
.notLessThanMin(defaultDifferentialLendingRate);
}
final Boolean isFloatingInterestRateCalculationAllowed = this.fromApiJsonHelper
.extractBooleanNamed(IS_FLOATING_INTEREST_RATE_CALCULATION_ALLOWED, element);
baseDataValidator.reset().parameter(IS_FLOATING_INTEREST_RATE_CALCULATION_ALLOWED)
.value(isFloatingInterestRateCalculationAllowed).notNull().isOneOfTheseValues(true, false);
isInterestBearing = true;
} else {
if (this.fromApiJsonHelper.parameterExists(FLOATING_RATES_ID, element)) {
baseDataValidator.reset().parameter(FLOATING_RATES_ID).failWithCode(
"not.supported.when.isLinkedToFloatingInterestRates.is.false",
"floatingRatesId param is not supported when isLinkedToFloatingInterestRates is not supplied or false");
}
if (this.fromApiJsonHelper.parameterExists(INTEREST_RATE_DIFFERENTIAL, element)) {
baseDataValidator.reset().parameter(INTEREST_RATE_DIFFERENTIAL).failWithCode(
"not.supported.when.isLinkedToFloatingInterestRates.is.false",
"interestRateDifferential param is not supported when isLinkedToFloatingInterestRates is not supplied or false");
}
if (this.fromApiJsonHelper.parameterExists(MIN_DIFFERENTIAL_LENDING_RATE, element)) {
baseDataValidator.reset().parameter(MIN_DIFFERENTIAL_LENDING_RATE).failWithCode(
"not.supported.when.isLinkedToFloatingInterestRates.is.false",
"minDifferentialLendingRate param is not supported when isLinkedToFloatingInterestRates is not supplied or false");
}
if (this.fromApiJsonHelper.parameterExists(DEFAULT_DIFFERENTIAL_LENDING_RATE, element)) {
baseDataValidator.reset().parameter(DEFAULT_DIFFERENTIAL_LENDING_RATE).failWithCode(
"not.supported.when.isLinkedToFloatingInterestRates.is.false",
"defaultDifferentialLendingRate param is not supported when isLinkedToFloatingInterestRates is not supplied or false");
}
if (this.fromApiJsonHelper.parameterExists(MAX_DIFFERENTIAL_LENDING_RATE, element)) {
baseDataValidator.reset().parameter(MAX_DIFFERENTIAL_LENDING_RATE).failWithCode(
"not.supported.when.isLinkedToFloatingInterestRates.is.false",
"maxDifferentialLendingRate param is not supported when isLinkedToFloatingInterestRates is not supplied or false");
}
if (this.fromApiJsonHelper.parameterExists(IS_FLOATING_INTEREST_RATE_CALCULATION_ALLOWED, element)) {
baseDataValidator.reset().parameter(IS_FLOATING_INTEREST_RATE_CALCULATION_ALLOWED).failWithCode(
"not.supported.when.isLinkedToFloatingInterestRates.is.false",
"isFloatingInterestRateCalculationAllowed param is not supported when isLinkedToFloatingInterestRates is not supplied or false");
}
BigDecimal interestRatePerPeriod = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(INTEREST_RATE_PER_PERIOD, element);
baseDataValidator.reset().parameter(INTEREST_RATE_PER_PERIOD).value(interestRatePerPeriod).notNull().zeroOrPositiveAmount();
final String minInterestRatePerPeriodParameterName = MIN_INTEREST_RATE_PER_PERIOD;
BigDecimal minInterestRatePerPeriod = null;
if (this.fromApiJsonHelper.parameterExists(minInterestRatePerPeriodParameterName, element)) {
minInterestRatePerPeriod = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minInterestRatePerPeriodParameterName,
element);
baseDataValidator.reset().parameter(minInterestRatePerPeriodParameterName).value(minInterestRatePerPeriod).ignoreIfNull()
.zeroOrPositiveAmount();
}
final String maxInterestRatePerPeriodParameterName = MAX_INTEREST_RATE_PER_PERIOD;
BigDecimal maxInterestRatePerPeriod = null;
if (this.fromApiJsonHelper.parameterExists(maxInterestRatePerPeriodParameterName, element)) {
maxInterestRatePerPeriod = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(maxInterestRatePerPeriodParameterName,
element);
baseDataValidator.reset().parameter(maxInterestRatePerPeriodParameterName).value(maxInterestRatePerPeriod).ignoreIfNull()
.zeroOrPositiveAmount();
}
if (maxInterestRatePerPeriod != null && maxInterestRatePerPeriod.compareTo(BigDecimal.ZERO) >= 0) {
if (minInterestRatePerPeriod != null && minInterestRatePerPeriod.compareTo(BigDecimal.ZERO) >= 0) {
baseDataValidator.reset().parameter(maxInterestRatePerPeriodParameterName).value(maxInterestRatePerPeriod)
.notLessThanMin(minInterestRatePerPeriod);
if (minInterestRatePerPeriod.compareTo(maxInterestRatePerPeriod) <= 0) {
baseDataValidator.reset().parameter(INTEREST_RATE_PER_PERIOD).value(interestRatePerPeriod)
.inMinAndMaxAmountRange(minInterestRatePerPeriod, maxInterestRatePerPeriod);
}
} else {
baseDataValidator.reset().parameter(INTEREST_RATE_PER_PERIOD).value(interestRatePerPeriod)
.notGreaterThanMax(maxInterestRatePerPeriod);
}
} else if (minInterestRatePerPeriod != null && minInterestRatePerPeriod.compareTo(BigDecimal.ZERO) >= 0) {
baseDataValidator.reset().parameter(INTEREST_RATE_PER_PERIOD).value(interestRatePerPeriod)
.notLessThanMin(minInterestRatePerPeriod);
}
final Integer interestRateFrequencyType = this.fromApiJsonHelper.extractIntegerNamed(INTEREST_RATE_FREQUENCY_TYPE, element,
Locale.getDefault());
baseDataValidator.reset().parameter(INTEREST_RATE_FREQUENCY_TYPE).value(interestRateFrequencyType).notNull().inMinMaxRange(0,
4);
isInterestBearing = MathUtil.isGreaterThanZero(interestRatePerPeriod);
}
// Fixed Length validation
fixedLengthValidations(transactionProcessingStrategyCode, isInterestBearing, numberOfRepayments, repaymentEvery, element,
baseDataValidator);
// Guarantee Funds
Boolean holdGuaranteeFunds = false;
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.holdGuaranteeFundsParamName, element)) {
holdGuaranteeFunds = this.fromApiJsonHelper.extractBooleanNamed(LoanProductConstants.holdGuaranteeFundsParamName, element);
baseDataValidator.reset().parameter(LoanProductConstants.holdGuaranteeFundsParamName).value(holdGuaranteeFunds).notNull()
.isOneOfTheseValues(true, false);
}
if (holdGuaranteeFunds != null && holdGuaranteeFunds) {
validateGuaranteeParams(element, baseDataValidator, null);
}
BigDecimal principalThresholdForLastInstallment = this.fromApiJsonHelper
.extractBigDecimalWithLocaleNamed(LoanProductConstants.principalThresholdForLastInstallmentParamName, element);
baseDataValidator.reset().parameter(LoanProductConstants.principalThresholdForLastInstallmentParamName)
.value(principalThresholdForLastInstallment).notLessThanMin(BigDecimal.ZERO).notGreaterThanMax(BigDecimal.valueOf(100));
BigDecimal fixedPrincipalPercentagePerInstallment = this.fromApiJsonHelper
.extractBigDecimalWithLocaleNamed(LoanProductConstants.fixedPrincipalPercentagePerInstallmentParamName, element);
baseDataValidator.reset().parameter(LoanProductConstants.fixedPrincipalPercentagePerInstallmentParamName)
.value(fixedPrincipalPercentagePerInstallment).notLessThanMin(BigDecimal.ONE).notGreaterThanMax(BigDecimal.valueOf(100));
if (amortizationType != null && !amortizationType.equals(AmortizationMethod.EQUAL_PRINCIPAL.getValue())
&& fixedPrincipalPercentagePerInstallment != null) {
baseDataValidator.reset().parameter(LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName).failWithCode(
"not.supported.principal.fixing.not.allowed.with.equal.installments",
"Principal fixing cannot be done with equal installment amortization");
}
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.canDefineEmiAmountParamName, element)) {
final Boolean canDefineInstallmentAmount = this.fromApiJsonHelper
.extractBooleanNamed(LoanProductConstants.canDefineEmiAmountParamName, element);
baseDataValidator.reset().parameter(LoanProductConstants.canDefineEmiAmountParamName).value(canDefineInstallmentAmount)
.isOneOfTheseValues(true, false);
}
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.installmentAmountInMultiplesOfParamName, element)) {
final Integer installmentAmountInMultiplesOf = this.fromApiJsonHelper
.extractIntegerWithLocaleNamed(LoanProductConstants.installmentAmountInMultiplesOfParamName, element);
baseDataValidator.reset().parameter(LoanProductConstants.installmentAmountInMultiplesOfParamName)
.value(installmentAmountInMultiplesOf).ignoreIfNull().integerGreaterThanZero();
}
// accounting related data validation
final Integer accountingRuleType = this.fromApiJsonHelper.extractIntegerNamed(ACCOUNTING_RULE, element, Locale.getDefault());
baseDataValidator.reset().parameter(ACCOUNTING_RULE).value(accountingRuleType).notNull().inMinMaxRange(1, 4);
if (AccountingValidations.isCashBasedAccounting(accountingRuleType)
|| AccountingValidations.isAccrualBasedAccounting(accountingRuleType)) {
final Long fundAccountId = this.fromApiJsonHelper.extractLongNamed(LoanProductAccountingParams.FUND_SOURCE.getValue(), element);
baseDataValidator.reset().parameter(LoanProductAccountingParams.FUND_SOURCE.getValue()).value(fundAccountId).notNull()
.integerGreaterThanZero();
final Long loanPortfolioAccountId = this.fromApiJsonHelper
.extractLongNamed(LoanProductAccountingParams.LOAN_PORTFOLIO.getValue(), element);
baseDataValidator.reset().parameter(LoanProductAccountingParams.LOAN_PORTFOLIO.getValue()).value(loanPortfolioAccountId)
.notNull().integerGreaterThanZero();
final Long transfersInSuspenseAccountId = this.fromApiJsonHelper
.extractLongNamed(LoanProductAccountingParams.TRANSFERS_SUSPENSE.getValue(), element);
baseDataValidator.reset().parameter(LoanProductAccountingParams.TRANSFERS_SUSPENSE.getValue())
.value(transfersInSuspenseAccountId).notNull().integerGreaterThanZero();
final Long incomeFromInterestId = this.fromApiJsonHelper
.extractLongNamed(LoanProductAccountingParams.INTEREST_ON_LOANS.getValue(), element);
baseDataValidator.reset().parameter(LoanProductAccountingParams.INTEREST_ON_LOANS.getValue()).value(incomeFromInterestId)
.notNull().integerGreaterThanZero();
final Long incomeFromFeeId = this.fromApiJsonHelper.extractLongNamed(LoanProductAccountingParams.INCOME_FROM_FEES.getValue(),
element);
baseDataValidator.reset().parameter(LoanProductAccountingParams.INCOME_FROM_FEES.getValue()).value(incomeFromFeeId).notNull()
.integerGreaterThanZero();
final Long incomeFromPenaltyId = this.fromApiJsonHelper
.extractLongNamed(LoanProductAccountingParams.INCOME_FROM_PENALTIES.getValue(), element);
baseDataValidator.reset().parameter(LoanProductAccountingParams.INCOME_FROM_PENALTIES.getValue()).value(incomeFromPenaltyId)
.notNull().integerGreaterThanZero();
final Long incomeFromRecoveryAccountId = this.fromApiJsonHelper
.extractLongNamed(LoanProductAccountingParams.INCOME_FROM_RECOVERY.getValue(), element);
baseDataValidator.reset().parameter(LoanProductAccountingParams.INCOME_FROM_RECOVERY.getValue())
.value(incomeFromRecoveryAccountId).notNull().integerGreaterThanZero();
final Long writeOffAccountId = this.fromApiJsonHelper
.extractLongNamed(LoanProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(), element);
baseDataValidator.reset().parameter(LoanProductAccountingParams.LOSSES_WRITTEN_OFF.getValue()).value(writeOffAccountId)
.notNull().integerGreaterThanZero();
final Long goodwillCreditAccountId = this.fromApiJsonHelper
.extractLongNamed(LoanProductAccountingParams.GOODWILL_CREDIT.getValue(), element);
baseDataValidator.reset().parameter(LoanProductAccountingParams.GOODWILL_CREDIT.getValue()).value(goodwillCreditAccountId)
.ignoreIfNull().integerGreaterThanZero();
final Long overpaymentAccountId = this.fromApiJsonHelper.extractLongNamed(LoanProductAccountingParams.OVERPAYMENT.getValue(),
element);
baseDataValidator.reset().parameter(LoanProductAccountingParams.OVERPAYMENT.getValue()).value(overpaymentAccountId).notNull()
.integerGreaterThanZero();
final Long incomeFromChargeOffInterestAccountId = this.fromApiJsonHelper
.extractLongNamed(LoanProductAccountingParams.INCOME_FROM_CHARGE_OFF_INTEREST.getValue(), element);
baseDataValidator.reset().parameter(LoanProductAccountingParams.INCOME_FROM_CHARGE_OFF_INTEREST.getValue())
.value(incomeFromChargeOffInterestAccountId).ignoreIfNull().integerGreaterThanZero();
final Long incomeFromChargeOffFeesAccountId = this.fromApiJsonHelper
.extractLongNamed(LoanProductAccountingParams.INCOME_FROM_CHARGE_OFF_FEES.getValue(), element);
baseDataValidator.reset().parameter(LoanProductAccountingParams.INCOME_FROM_CHARGE_OFF_FEES.getValue())
.value(incomeFromChargeOffFeesAccountId).ignoreIfNull().integerGreaterThanZero();
final Long incomeFromChargeOffPenaltyAccountId = this.fromApiJsonHelper
.extractLongNamed(LoanProductAccountingParams.INCOME_FROM_CHARGE_OFF_PENALTY.getValue(), element);
baseDataValidator.reset().parameter(LoanProductAccountingParams.INCOME_FROM_CHARGE_OFF_PENALTY.getValue())
.value(incomeFromChargeOffPenaltyAccountId).ignoreIfNull().integerGreaterThanZero();
final Long incomeFromGoodwillCreditInterestAccountId = this.fromApiJsonHelper
.extractLongNamed(LoanProductAccountingParams.INCOME_FROM_GOODWILL_CREDIT_INTEREST.getValue(), element);
baseDataValidator.reset().parameter(LoanProductAccountingParams.INCOME_FROM_GOODWILL_CREDIT_INTEREST.getValue())
.value(incomeFromGoodwillCreditInterestAccountId).ignoreIfNull().integerGreaterThanZero();
final Long incomeFromGoodwillCreditFeesAccountId = this.fromApiJsonHelper
.extractLongNamed(LoanProductAccountingParams.INCOME_FROM_GOODWILL_CREDIT_FEES.getValue(), element);
baseDataValidator.reset().parameter(LoanProductAccountingParams.INCOME_FROM_GOODWILL_CREDIT_FEES.getValue())
.value(incomeFromGoodwillCreditFeesAccountId).ignoreIfNull().integerGreaterThanZero();
final Long incomeFromGoodwillCreditPenaltyAccountId = this.fromApiJsonHelper
.extractLongNamed(LoanProductAccountingParams.INCOME_FROM_GOODWILL_CREDIT_PENALTY.getValue(), element);
baseDataValidator.reset().parameter(LoanProductAccountingParams.INCOME_FROM_GOODWILL_CREDIT_PENALTY.getValue())
.value(incomeFromGoodwillCreditPenaltyAccountId).ignoreIfNull().integerGreaterThanZero();
final Long chargeOffExpenseAccountId = this.fromApiJsonHelper
.extractLongNamed(LoanProductAccountingParams.CHARGE_OFF_EXPENSE.getValue(), element);
baseDataValidator.reset().parameter(LoanProductAccountingParams.CHARGE_OFF_EXPENSE.getValue()).value(chargeOffExpenseAccountId)
.ignoreIfNull().integerGreaterThanZero();
final Long chargeOffFraudExpenseAccountId = this.fromApiJsonHelper
.extractLongNamed(LoanProductAccountingParams.CHARGE_OFF_FRAUD_EXPENSE.getValue(), element);
baseDataValidator.reset().parameter(LoanProductAccountingParams.CHARGE_OFF_FRAUD_EXPENSE.getValue())
.value(chargeOffFraudExpenseAccountId).ignoreIfNull().integerGreaterThanZero();
validatePaymentChannelFundSourceMappings(baseDataValidator, element);
validateChargeToIncomeAccountMappings(baseDataValidator, element);
validateChargeOffToExpenseMappings(baseDataValidator, element);
}
if (AccountingValidations.isAccrualBasedAccounting(accountingRuleType)) {
final Long receivableInterestAccountId = this.fromApiJsonHelper
.extractLongNamed(LoanProductAccountingParams.INTEREST_RECEIVABLE.getValue(), element);
baseDataValidator.reset().parameter(LoanProductAccountingParams.INTEREST_RECEIVABLE.getValue())
.value(receivableInterestAccountId).notNull().integerGreaterThanZero();
final Long receivableFeeAccountId = this.fromApiJsonHelper
.extractLongNamed(LoanProductAccountingParams.FEES_RECEIVABLE.getValue(), element);
baseDataValidator.reset().parameter(LoanProductAccountingParams.FEES_RECEIVABLE.getValue()).value(receivableFeeAccountId)
.notNull().integerGreaterThanZero();
final Long receivablePenaltyAccountId = this.fromApiJsonHelper
.extractLongNamed(LoanProductAccountingParams.PENALTIES_RECEIVABLE.getValue(), element);
baseDataValidator.reset().parameter(LoanProductAccountingParams.PENALTIES_RECEIVABLE.getValue())
.value(receivablePenaltyAccountId).notNull().integerGreaterThanZero();
}
if (!AccountingValidations.isAccrualBasedAccounting(accountingRuleType)
&& this.fromApiJsonHelper.parameterExists(LoanProductConstants.ENABLE_ACCRUAL_ACTIVITY_POSTING, element)) {
final Boolean enableAccrualActivityPosting = this.fromApiJsonHelper
.extractBooleanNamed(LoanProductConstants.ENABLE_ACCRUAL_ACTIVITY_POSTING, element);
baseDataValidator.reset().parameter(LoanProductConstants.ENABLE_ACCRUAL_ACTIVITY_POSTING).value(enableAccrualActivityPosting)
.ignoreIfNull().validateForBooleanValue();
if (!AccountingValidations.isAccrualBasedAccounting(accountingRuleType)) {
baseDataValidator.reset().parameter(LoanProductConstants.ENABLE_ACCRUAL_ACTIVITY_POSTING).isOneOfTheseValues(Boolean.TRUE)
.failWithCode("should be false for non accrual accounting");
}
}
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.USE_BORROWER_CYCLE_PARAMETER_NAME, element)) {
final Boolean useBorrowerCycle = this.fromApiJsonHelper
.extractBooleanNamed(LoanProductConstants.USE_BORROWER_CYCLE_PARAMETER_NAME, element);
baseDataValidator.reset().parameter(LoanProductConstants.USE_BORROWER_CYCLE_PARAMETER_NAME).value(useBorrowerCycle)
.ignoreIfNull().validateForBooleanValue();
if (useBorrowerCycle) {
validateBorrowerCycleVariations(element, baseDataValidator);
}
}
validateMultiDisburseLoanData(baseDataValidator, element);
validateLoanConfigurableAttributes(baseDataValidator, element);
validateVariableInstallmentSettings(baseDataValidator, element);
validatePartialPeriodSupport(interestCalculationPeriodType, baseDataValidator, element, null);
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.CAN_USE_FOR_TOPUP, element)) {
final Boolean canUseForTopup = this.fromApiJsonHelper.extractBooleanNamed(LoanProductConstants.CAN_USE_FOR_TOPUP, element);
baseDataValidator.reset().parameter(LoanProductConstants.CAN_USE_FOR_TOPUP).value(canUseForTopup).validateForBooleanValue();
}
final Integer dueDaysForRepaymentEvent = this.fromApiJsonHelper
.extractIntegerWithLocaleNamed(LoanProductConstants.DUE_DAYS_FOR_REPAYMENT_EVENT, element);
baseDataValidator.reset().parameter(LoanProductConstants.DUE_DAYS_FOR_REPAYMENT_EVENT).value(dueDaysForRepaymentEvent)
.integerZeroOrGreater();
final Integer overDueDaysForRepaymentEvent = this.fromApiJsonHelper
.extractIntegerWithLocaleNamed(LoanProductConstants.OVER_DUE_DAYS_FOR_REPAYMENT_EVENT, element);
baseDataValidator.reset().parameter(LoanProductConstants.OVER_DUE_DAYS_FOR_REPAYMENT_EVENT).value(overDueDaysForRepaymentEvent)
.integerZeroOrGreater();
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.ENABLE_DOWN_PAYMENT, element)) {
final Boolean enableDownPayment = this.fromApiJsonHelper.extractBooleanNamed(LoanProductConstants.ENABLE_DOWN_PAYMENT, element);
baseDataValidator.reset().parameter(LoanProductConstants.ENABLE_DOWN_PAYMENT).value(enableDownPayment).ignoreIfNull()
.validateForBooleanValue();
validateDownPaymentPercentage(enableDownPayment, baseDataValidator, element);
validateAutoRepaymentForDownPayment(enableDownPayment, baseDataValidator, element);
}
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.REPAYMENT_START_DATE_TYPE, element)) {
final Integer repaymentStartDateType = this.fromApiJsonHelper
.extractIntegerNamed(LoanProductConstants.REPAYMENT_START_DATE_TYPE, element, Locale.getDefault());
baseDataValidator.reset().parameter(LoanProductConstants.REPAYMENT_START_DATE_TYPE).value(repaymentStartDateType).notNull()
.isOneOfTheseValues(1, 2);
}
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY, element)) {
final Boolean enableInstallmentLevelDelinquency = this.fromApiJsonHelper
.extractBooleanNamed(LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY, element);
baseDataValidator.reset().parameter(LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY)
.value(enableInstallmentLevelDelinquency).ignoreIfNull().validateForBooleanValue();
if (delinquencyBucketId == null) {
if (enableInstallmentLevelDelinquency) {
baseDataValidator.reset().parameter(LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY).failWithCode(
"can.be.enabled.for.loan.product.having.valid.delinquency.bucket",
"Installment level delinquency cannot be enabled if Delinquency bucket is not configured for loan product");
}
}
}
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.LOAN_SCHEDULE_TYPE, element)) {
validateLoanScheduleType(transactionProcessingStrategyCode, baseDataValidator, element);
}
String loanScheduleProcessingType = LoanScheduleProcessingType.HORIZONTAL.name();
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.LOAN_SCHEDULE_PROCESSING_TYPE, element)) {
loanScheduleProcessingType = this.fromApiJsonHelper.extractStringNamed(LoanProductConstants.LOAN_SCHEDULE_PROCESSING_TYPE,
element);
baseDataValidator.reset().parameter(LoanProductConstants.LOAN_SCHEDULE_PROCESSING_TYPE).value(loanScheduleProcessingType)
.isOneOfEnumValues(LoanScheduleProcessingType.class);
if (LoanScheduleProcessingType.VERTICAL.equals(LoanScheduleProcessingType.valueOf(loanScheduleProcessingType))
&& !AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY
.equals(transactionProcessingStrategyCode)) {
baseDataValidator.reset().parameter(LoanProductConstants.LOAN_SCHEDULE_PROCESSING_TYPE).failWithCode(
"supported.only.for.progressive.loan.schedule.handling",
"Vertical repayment schedule processing is only available with `Advanced payment allocation` strategy");
}
}
if (AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY.equals(transactionProcessingStrategyCode)
&& LoanScheduleProcessingType.HORIZONTAL.name().equals(loanScheduleProcessingType)) {
advancedPaymentAllocationsValidator.checkGroupingOfAllocationRules(advancedPaymentAllocationsJsonParser
.assembleLoanProductPaymentAllocationRules(command, transactionProcessingStrategyCode));
}
final Integer recurringMoratoriumOnPrincipalPeriods = this.fromApiJsonHelper
.extractIntegerWithLocaleNamed("recurringMoratoriumOnPrincipalPeriods", element);
validateRepaymentPeriodWithGraceSettings(numberOfRepayments, graceOnPrincipalPayment, graceOnInterestPayment,
graceOnInterestCharged, recurringMoratoriumOnPrincipalPeriods, baseDataValidator);
if (AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY.equals(transactionProcessingStrategyCode)
&& this.fromApiJsonHelper.parameterExists(LoanProductConstants.SUPPORTED_INTEREST_REFUND_TYPES, element)) {
String[] supportedTransactionsForInterestRefund = this.fromApiJsonHelper
.extractArrayNamed(LoanProductConstants.SUPPORTED_INTEREST_REFUND_TYPES, element);
Arrays.stream(supportedTransactionsForInterestRefund)
.forEach(value -> baseDataValidator.reset().parameter(LoanProductConstants.SUPPORTED_INTEREST_REFUND_TYPES).value(value)
.isOneOfEnumValues(LoanSupportedInterestRefundTypes.class));
} else if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.SUPPORTED_INTEREST_REFUND_TYPES, element)) {
baseDataValidator.reset().parameter(LoanProductConstants.SUPPORTED_INTEREST_REFUND_TYPES).failWithCode(
"supported.only.for.progressive.loan.schedule.handling",
"Automatic interest refund functionality is only supported for Progressive loans");
}
if (AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY.equals(transactionProcessingStrategyCode)
&& this.fromApiJsonHelper.parameterExists(LoanProductConstants.CHARGE_OFF_BEHAVIOUR, element)) {
String chargeOffBehaviour = this.fromApiJsonHelper.extractStringNamed(LoanProductConstants.CHARGE_OFF_BEHAVIOUR, element);
baseDataValidator.reset().parameter(LoanProductConstants.CHARGE_OFF_BEHAVIOUR).value(chargeOffBehaviour)
.isOneOfEnumValues(LoanChargeOffBehaviour.class);
} else if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.CHARGE_OFF_BEHAVIOUR, element)) {
baseDataValidator.reset().parameter(LoanProductConstants.CHARGE_OFF_BEHAVIOUR).failWithCode(
"supported.only.for.progressive.loan.charge.off.behaviour",
"Charge off behaviour is only supported for Progressive loans");
}
validateIncomeCapitalization(transactionProcessingStrategyCode, element, baseDataValidator, accountingRuleType);
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}