FINERACT-1761-Repayment-due-event-configuration-at-product-level
This commit is contained in:
committed by
Arnold Gálovics
parent
5fe708a90f
commit
57a1cb2f8c
+5
@@ -42,6 +42,11 @@ public class CheckLoanRepaymentDueBusinessStep implements LoanCOBBusinessStep {
|
|||||||
public Loan execute(Loan loan) {
|
public Loan execute(Loan loan) {
|
||||||
log.debug("start processing loan repayment due business step loan for loan with id [{}]", loan.getId());
|
log.debug("start processing loan repayment due business step loan for loan with id [{}]", loan.getId());
|
||||||
Long numberOfDaysBeforeDueDateToRaiseEvent = configurationDomainService.retrieveRepaymentDueDays();
|
Long numberOfDaysBeforeDueDateToRaiseEvent = configurationDomainService.retrieveRepaymentDueDays();
|
||||||
|
if (loan.getLoanProduct().getDueDaysForRepaymentEvent() != null) {
|
||||||
|
if (loan.getLoanProduct().getDueDaysForRepaymentEvent() > 0) {
|
||||||
|
numberOfDaysBeforeDueDateToRaiseEvent = loan.getLoanProduct().getDueDaysForRepaymentEvent().longValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
final LocalDate currentDate = DateUtils.getBusinessLocalDate();
|
final LocalDate currentDate = DateUtils.getBusinessLocalDate();
|
||||||
final List<LoanRepaymentScheduleInstallment> loanRepaymentScheduleInstallments = loan.getRepaymentScheduleInstallments();
|
final List<LoanRepaymentScheduleInstallment> loanRepaymentScheduleInstallments = loan.getRepaymentScheduleInstallments();
|
||||||
for (LoanRepaymentScheduleInstallment repaymentSchedule : loanRepaymentScheduleInstallments) {
|
for (LoanRepaymentScheduleInstallment repaymentSchedule : loanRepaymentScheduleInstallments) {
|
||||||
|
|||||||
+5
@@ -42,6 +42,11 @@ public class CheckLoanRepaymentOverdueBusinessStep implements LoanCOBBusinessSte
|
|||||||
public Loan execute(Loan loan) {
|
public Loan execute(Loan loan) {
|
||||||
log.debug("start processing loan repayment overdue business step for loan with Id [{}]", loan.getId());
|
log.debug("start processing loan repayment overdue business step for loan with Id [{}]", loan.getId());
|
||||||
Long numberOfDaysAfterDueDateToRaiseEvent = configurationDomainService.retrieveRepaymentOverdueDays();
|
Long numberOfDaysAfterDueDateToRaiseEvent = configurationDomainService.retrieveRepaymentOverdueDays();
|
||||||
|
if (loan.getLoanProduct().getOverDueDaysForRepaymentEvent() != null) {
|
||||||
|
if (loan.getLoanProduct().getOverDueDaysForRepaymentEvent() > 0) {
|
||||||
|
numberOfDaysAfterDueDateToRaiseEvent = loan.getLoanProduct().getOverDueDaysForRepaymentEvent().longValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
final LocalDate currentDate = DateUtils.getBusinessLocalDate();
|
final LocalDate currentDate = DateUtils.getBusinessLocalDate();
|
||||||
final List<LoanRepaymentScheduleInstallment> loanRepaymentScheduleInstallments = loan.getRepaymentScheduleInstallments();
|
final List<LoanRepaymentScheduleInstallment> loanRepaymentScheduleInstallments = loan.getRepaymentScheduleInstallments();
|
||||||
for (LoanRepaymentScheduleInstallment repaymentSchedule : loanRepaymentScheduleInstallments) {
|
for (LoanRepaymentScheduleInstallment repaymentSchedule : loanRepaymentScheduleInstallments) {
|
||||||
|
|||||||
+4
@@ -143,4 +143,8 @@ public interface LoanProductConstants {
|
|||||||
String OVER_APPLIED_NUMBER = "overAppliedNumber";
|
String OVER_APPLIED_NUMBER = "overAppliedNumber";
|
||||||
String DELINQUENCY_BUCKET_PARAM_NAME = "delinquencyBucketId";
|
String DELINQUENCY_BUCKET_PARAM_NAME = "delinquencyBucketId";
|
||||||
|
|
||||||
|
// repayment events related
|
||||||
|
String DUE_DAYS_FOR_REPAYMENT_EVENT = "dueDaysForRepaymentEvent";
|
||||||
|
String OVER_DUE_DAYS_FOR_REPAYMENT_EVENT = "overDueDaysForRepaymentEvent";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -106,7 +106,8 @@ public class LoanProductsApiResource {
|
|||||||
"isLinkedToFloatingInterestRates", "floatingRatesId", "interestRateDifferential", "minDifferentialLendingRate",
|
"isLinkedToFloatingInterestRates", "floatingRatesId", "interestRateDifferential", "minDifferentialLendingRate",
|
||||||
"defaultDifferentialLendingRate", "maxDifferentialLendingRate", "isFloatingInterestRateCalculationAllowed",
|
"defaultDifferentialLendingRate", "maxDifferentialLendingRate", "isFloatingInterestRateCalculationAllowed",
|
||||||
LoanProductConstants.CAN_USE_FOR_TOPUP, LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM, LoanProductConstants.RATES_PARAM_NAME,
|
LoanProductConstants.CAN_USE_FOR_TOPUP, LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM, LoanProductConstants.RATES_PARAM_NAME,
|
||||||
LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName));
|
LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName, LoanProductConstants.DUE_DAYS_FOR_REPAYMENT_EVENT,
|
||||||
|
LoanProductConstants.OVER_DUE_DAYS_FOR_REPAYMENT_EVENT));
|
||||||
|
|
||||||
private static final Set<String> PRODUCT_MIX_DATA_PARAMETERS = new HashSet<>(
|
private static final Set<String> PRODUCT_MIX_DATA_PARAMETERS = new HashSet<>(
|
||||||
Arrays.asList("productId", "productName", "restrictedProducts", "allowedProducts", "productOptions"));
|
Arrays.asList("productId", "productName", "restrictedProducts", "allowedProducts", "productOptions"));
|
||||||
@@ -141,7 +142,7 @@ public class LoanProductsApiResource {
|
|||||||
@Operation(summary = "Create a Loan Product", description = "Depending of the Accounting Rule (accountingRule) selected, additional fields with details of the appropriate Ledger Account identifiers would need to be passed in.\n"
|
@Operation(summary = "Create a Loan Product", description = "Depending of the Accounting Rule (accountingRule) selected, additional fields with details of the appropriate Ledger Account identifiers would need to be passed in.\n"
|
||||||
+ "\n" + "Refer MifosX Accounting Specs Draft for more details regarding the significance of the selected accounting rule\n\n"
|
+ "\n" + "Refer MifosX Accounting Specs Draft for more details regarding the significance of the selected accounting rule\n\n"
|
||||||
+ "Mandatory Fields: name, shortName, currencyCode, digitsAfterDecimal, inMultiplesOf, principal, numberOfRepayments, repaymentEvery, repaymentFrequencyType, interestRatePerPeriod, interestRateFrequencyType, amortizationType, interestType, interestCalculationPeriodType, transactionProcessingStrategyCode, accountingRule, isInterestRecalculationEnabled, daysInYearType, daysInMonthType\n\n"
|
+ "Mandatory Fields: name, shortName, currencyCode, digitsAfterDecimal, inMultiplesOf, principal, numberOfRepayments, repaymentEvery, repaymentFrequencyType, interestRatePerPeriod, interestRateFrequencyType, amortizationType, interestType, interestCalculationPeriodType, transactionProcessingStrategyCode, accountingRule, isInterestRecalculationEnabled, daysInYearType, daysInMonthType\n\n"
|
||||||
+ "Optional Fields: inArrearsTolerance, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, graceOnArrearsAgeing, charges, paymentChannelToFundSourceMappings, feeToIncomeAccountMappings, penaltyToIncomeAccountMappings, includeInBorrowerCycle, useBorrowerCycle,principalVariationsForBorrowerCycle, numberOfRepaymentVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle, multiDisburseLoan,maxTrancheCount, outstandingLoanBalance,overdueDaysForNPA,holdGuaranteeFunds, principalThresholdForLastInstalment, accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount, installmentAmountInMultiplesOf, allowAttributeOverrides, allowPartialPeriodInterestCalcualtion\n\n"
|
+ "Optional Fields: inArrearsTolerance, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, graceOnArrearsAgeing, charges, paymentChannelToFundSourceMappings, feeToIncomeAccountMappings, penaltyToIncomeAccountMappings, includeInBorrowerCycle, useBorrowerCycle,principalVariationsForBorrowerCycle, numberOfRepaymentVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle, multiDisburseLoan,maxTrancheCount, outstandingLoanBalance,overdueDaysForNPA,holdGuaranteeFunds, principalThresholdForLastInstalment, accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount, installmentAmountInMultiplesOf, allowAttributeOverrides, allowPartialPeriodInterestCalcualtion,dueDaysForRepaymentEvent,overDueDaysForRepaymentEvent\n\n"
|
||||||
+ "Additional Mandatory Fields for Cash(2) based accounting: fundSourceAccountId, loanPortfolioAccountId, interestOnLoanAccountId, incomeFromFeeAccountId, incomeFromPenaltyAccountId, writeOffAccountId, transfersInSuspenseAccountId, overpaymentLiabilityAccountId\n\n"
|
+ "Additional Mandatory Fields for Cash(2) based accounting: fundSourceAccountId, loanPortfolioAccountId, interestOnLoanAccountId, incomeFromFeeAccountId, incomeFromPenaltyAccountId, writeOffAccountId, transfersInSuspenseAccountId, overpaymentLiabilityAccountId\n\n"
|
||||||
+ "Additional Mandatory Fields for periodic (3) and upfront (4)accrual accounting: fundSourceAccountId, loanPortfolioAccountId, interestOnLoanAccountId, incomeFromFeeAccountId, incomeFromPenaltyAccountId, writeOffAccountId, receivableInterestAccountId, receivableFeeAccountId, receivablePenaltyAccountId, transfersInSuspenseAccountId, overpaymentLiabilityAccountId\n\n"
|
+ "Additional Mandatory Fields for periodic (3) and upfront (4)accrual accounting: fundSourceAccountId, loanPortfolioAccountId, interestOnLoanAccountId, incomeFromFeeAccountId, incomeFromPenaltyAccountId, writeOffAccountId, receivableInterestAccountId, receivableFeeAccountId, receivablePenaltyAccountId, transfersInSuspenseAccountId, overpaymentLiabilityAccountId\n\n"
|
||||||
+ "Additional Mandatory Fields if interest recalculation is enabled(true): interestRecalculationCompoundingMethod, rescheduleStrategyMethod, recalculationRestFrequencyType\n\n"
|
+ "Additional Mandatory Fields if interest recalculation is enabled(true): interestRecalculationCompoundingMethod, rescheduleStrategyMethod, recalculationRestFrequencyType\n\n"
|
||||||
|
|||||||
+12
@@ -149,6 +149,10 @@ final class LoanProductsApiResourceSwagger {
|
|||||||
public Boolean holdGuaranteeFunds;
|
public Boolean holdGuaranteeFunds;
|
||||||
@Schema(example = "1")
|
@Schema(example = "1")
|
||||||
public Long delinquencyBucketId;
|
public Long delinquencyBucketId;
|
||||||
|
@Schema(example = "3")
|
||||||
|
public Integer dueDaysForRepaymentEvent;
|
||||||
|
@Schema(example = "3")
|
||||||
|
public Integer overDueDaysForRepaymentEvent;
|
||||||
|
|
||||||
// Interest Recalculation
|
// Interest Recalculation
|
||||||
@Schema(example = "false")
|
@Schema(example = "false")
|
||||||
@@ -1191,6 +1195,10 @@ final class LoanProductsApiResourceSwagger {
|
|||||||
public GetDelinquencyBucketsResponse delinquencyBucket;
|
public GetDelinquencyBucketsResponse delinquencyBucket;
|
||||||
@Schema(example = "true")
|
@Schema(example = "true")
|
||||||
public Boolean disallowExpectedDisbursements;
|
public Boolean disallowExpectedDisbursements;
|
||||||
|
@Schema(example = "3")
|
||||||
|
public Integer dueDaysForRepaymentEvent;
|
||||||
|
@Schema(example = "3")
|
||||||
|
public Integer overDueDaysForRepaymentEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Schema(description = "PutLoanProductsProductIdRequest")
|
@Schema(description = "PutLoanProductsProductIdRequest")
|
||||||
@@ -1308,6 +1316,10 @@ final class LoanProductsApiResourceSwagger {
|
|||||||
public Boolean holdGuaranteeFunds;
|
public Boolean holdGuaranteeFunds;
|
||||||
@Schema(example = "1")
|
@Schema(example = "1")
|
||||||
public Long delinquencyBucketId;
|
public Long delinquencyBucketId;
|
||||||
|
@Schema(example = "3")
|
||||||
|
public Integer dueDaysForRepaymentEvent;
|
||||||
|
@Schema(example = "3")
|
||||||
|
public Integer overDueDaysForRepaymentEvent;
|
||||||
|
|
||||||
// Interest Recalculation
|
// Interest Recalculation
|
||||||
@Schema(example = "false")
|
@Schema(example = "false")
|
||||||
|
|||||||
+25
-5
@@ -190,6 +190,9 @@ public class LoanProductData implements Serializable {
|
|||||||
private final Collection<DelinquencyBucketData> delinquencyBucketOptions;
|
private final Collection<DelinquencyBucketData> delinquencyBucketOptions;
|
||||||
private final DelinquencyBucketData delinquencyBucket;
|
private final DelinquencyBucketData delinquencyBucket;
|
||||||
|
|
||||||
|
private final Integer dueDaysForRepaymentEvent;
|
||||||
|
private final Integer overDueDaysForRepaymentEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used when returning lookup information about loan product for dropdowns.
|
* Used when returning lookup information about loan product for dropdowns.
|
||||||
*/
|
*/
|
||||||
@@ -276,6 +279,8 @@ public class LoanProductData implements Serializable {
|
|||||||
final boolean isRatesEnabled = false;
|
final boolean isRatesEnabled = false;
|
||||||
final Collection<DelinquencyBucketData> delinquencyBucketOptions = null;
|
final Collection<DelinquencyBucketData> delinquencyBucketOptions = null;
|
||||||
final DelinquencyBucketData delinquencyBucket = null;
|
final DelinquencyBucketData delinquencyBucket = null;
|
||||||
|
final Integer dueDaysForRepaymentEvent = null;
|
||||||
|
final Integer overDueDaysForRepaymentEvent = null;
|
||||||
|
|
||||||
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
||||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
||||||
@@ -293,7 +298,8 @@ public class LoanProductData implements Serializable {
|
|||||||
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
||||||
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap,
|
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap,
|
||||||
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
|
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
|
||||||
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket);
|
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
|
||||||
|
overDueDaysForRepaymentEvent);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,6 +387,8 @@ public class LoanProductData implements Serializable {
|
|||||||
final boolean isRatesEnabled = false;
|
final boolean isRatesEnabled = false;
|
||||||
final Collection<DelinquencyBucketData> delinquencyBucketOptions = null;
|
final Collection<DelinquencyBucketData> delinquencyBucketOptions = null;
|
||||||
final DelinquencyBucketData delinquencyBucket = null;
|
final DelinquencyBucketData delinquencyBucket = null;
|
||||||
|
final Integer dueDaysForRepaymentEvent = null;
|
||||||
|
final Integer overDueDaysForRepaymentEvent = null;
|
||||||
|
|
||||||
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
||||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
||||||
@@ -398,7 +406,8 @@ public class LoanProductData implements Serializable {
|
|||||||
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
||||||
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap,
|
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap,
|
||||||
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
|
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
|
||||||
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket);
|
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
|
||||||
|
overDueDaysForRepaymentEvent);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -493,6 +502,8 @@ public class LoanProductData implements Serializable {
|
|||||||
final boolean isRatesEnabled = false;
|
final boolean isRatesEnabled = false;
|
||||||
final Collection<DelinquencyBucketData> delinquencyBucketOptions = null;
|
final Collection<DelinquencyBucketData> delinquencyBucketOptions = null;
|
||||||
final DelinquencyBucketData delinquencyBucket = null;
|
final DelinquencyBucketData delinquencyBucket = null;
|
||||||
|
final Integer dueDaysForRepaymentEvent = null;
|
||||||
|
final Integer overDueDaysForRepaymentEvent = null;
|
||||||
|
|
||||||
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
||||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
||||||
@@ -510,7 +521,8 @@ public class LoanProductData implements Serializable {
|
|||||||
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
||||||
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap,
|
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap,
|
||||||
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
|
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
|
||||||
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket);
|
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
|
||||||
|
overDueDaysForRepaymentEvent);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -599,6 +611,8 @@ public class LoanProductData implements Serializable {
|
|||||||
final boolean isRatesEnabled = false;
|
final boolean isRatesEnabled = false;
|
||||||
final Collection<DelinquencyBucketData> delinquencyBucketOptions = null;
|
final Collection<DelinquencyBucketData> delinquencyBucketOptions = null;
|
||||||
final DelinquencyBucketData delinquencyBucket = null;
|
final DelinquencyBucketData delinquencyBucket = null;
|
||||||
|
final Integer dueDaysForRepaymentEvent = null;
|
||||||
|
final Integer overDueDaysForRepaymentEvent = null;
|
||||||
|
|
||||||
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
||||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
||||||
@@ -616,7 +630,8 @@ public class LoanProductData implements Serializable {
|
|||||||
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
||||||
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap,
|
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap,
|
||||||
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
|
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
|
||||||
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket);
|
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
|
||||||
|
overDueDaysForRepaymentEvent);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -662,7 +677,8 @@ public class LoanProductData implements Serializable {
|
|||||||
final boolean syncExpectedWithDisbursementDate, final boolean canUseForTopup, final boolean isEqualAmortization,
|
final boolean syncExpectedWithDisbursementDate, final boolean canUseForTopup, final boolean isEqualAmortization,
|
||||||
Collection<RateData> rateOptions, Collection<RateData> rates, final boolean isRatesEnabled,
|
Collection<RateData> rateOptions, Collection<RateData> rates, final boolean isRatesEnabled,
|
||||||
final BigDecimal fixedPrincipalPercentagePerInstallment, final Collection<DelinquencyBucketData> delinquencyBucketOptions,
|
final BigDecimal fixedPrincipalPercentagePerInstallment, final Collection<DelinquencyBucketData> delinquencyBucketOptions,
|
||||||
final DelinquencyBucketData delinquencyBucket) {
|
final DelinquencyBucketData delinquencyBucket, final Integer dueDaysForRepaymentEvent,
|
||||||
|
final Integer overDueDaysForRepaymentEvent) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.shortName = shortName;
|
this.shortName = shortName;
|
||||||
@@ -778,6 +794,8 @@ public class LoanProductData implements Serializable {
|
|||||||
this.isEqualAmortization = isEqualAmortization;
|
this.isEqualAmortization = isEqualAmortization;
|
||||||
this.delinquencyBucketOptions = delinquencyBucketOptions;
|
this.delinquencyBucketOptions = delinquencyBucketOptions;
|
||||||
this.delinquencyBucket = delinquencyBucket;
|
this.delinquencyBucket = delinquencyBucket;
|
||||||
|
this.dueDaysForRepaymentEvent = dueDaysForRepaymentEvent;
|
||||||
|
this.overDueDaysForRepaymentEvent = overDueDaysForRepaymentEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoanProductData(final LoanProductData productData, final Collection<ChargeData> chargeOptions,
|
public LoanProductData(final LoanProductData productData, final Collection<ChargeData> chargeOptions,
|
||||||
@@ -927,6 +945,8 @@ public class LoanProductData implements Serializable {
|
|||||||
this.isRatesEnabled = isRatesEnabled;
|
this.isRatesEnabled = isRatesEnabled;
|
||||||
this.delinquencyBucketOptions = delinquencyBucketOptions;
|
this.delinquencyBucketOptions = delinquencyBucketOptions;
|
||||||
this.delinquencyBucket = productData.delinquencyBucket;
|
this.delinquencyBucket = productData.delinquencyBucket;
|
||||||
|
this.dueDaysForRepaymentEvent = productData.dueDaysForRepaymentEvent;
|
||||||
|
this.overDueDaysForRepaymentEvent = productData.overDueDaysForRepaymentEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Collection<ChargeData> nullIfEmpty(final Collection<ChargeData> charges) {
|
private Collection<ChargeData> nullIfEmpty(final Collection<ChargeData> charges) {
|
||||||
|
|||||||
+40
-2
@@ -202,6 +202,12 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
@JoinColumn(name = "delinquency_bucket_id")
|
@JoinColumn(name = "delinquency_bucket_id")
|
||||||
private DelinquencyBucket delinquencyBucket;
|
private DelinquencyBucket delinquencyBucket;
|
||||||
|
|
||||||
|
@Column(name = "due_days_for_repayment_event")
|
||||||
|
private Integer dueDaysForRepaymentEvent;
|
||||||
|
|
||||||
|
@Column(name = "overdue_days_for_repayment_event")
|
||||||
|
private Integer overDueDaysForRepaymentEvent;
|
||||||
|
|
||||||
public static LoanProduct assembleFromJson(final Fund fund, final String loanTransactionProcessingStrategy,
|
public static LoanProduct assembleFromJson(final Fund fund, final String loanTransactionProcessingStrategy,
|
||||||
final List<Charge> productCharges, final JsonCommand command, final AprCalculator aprCalculator, FloatingRate floatingRate,
|
final List<Charge> productCharges, final JsonCommand command, final AprCalculator aprCalculator, FloatingRate floatingRate,
|
||||||
final List<Rate> productRates) {
|
final List<Rate> productRates) {
|
||||||
@@ -373,6 +379,10 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
|
|
||||||
final Integer overAppliedNumber = command.integerValueOfParameterNamed(LoanProductConstants.OVER_APPLIED_NUMBER);
|
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);
|
||||||
|
|
||||||
return new LoanProduct(fund, loanTransactionProcessingStrategy, name, shortName, description, currency, principal, minPrincipal,
|
return new LoanProduct(fund, loanTransactionProcessingStrategy, name, shortName, description, currency, principal, minPrincipal,
|
||||||
maxPrincipal, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, interestFrequencyType,
|
maxPrincipal, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, interestFrequencyType,
|
||||||
annualInterestRate, interestMethod, interestCalculationPeriodMethod, allowPartialPeriodInterestCalcualtion, repaymentEvery,
|
annualInterestRate, interestMethod, interestCalculationPeriodMethod, allowPartialPeriodInterestCalcualtion, repaymentEvery,
|
||||||
@@ -388,7 +398,8 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
defaultDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed,
|
defaultDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed,
|
||||||
minimumGapBetweenInstallments, maximumGapBetweenInstallments, syncExpectedWithDisbursementDate, canUseForTopup,
|
minimumGapBetweenInstallments, maximumGapBetweenInstallments, syncExpectedWithDisbursementDate, canUseForTopup,
|
||||||
isEqualAmortization, productRates, fixedPrincipalPercentagePerInstallment, disallowExpectedDisbursements,
|
isEqualAmortization, productRates, fixedPrincipalPercentagePerInstallment, disallowExpectedDisbursements,
|
||||||
allowApprovedDisbursedAmountsOverApplied, overAppliedCalculationType, overAppliedNumber);
|
allowApprovedDisbursedAmountsOverApplied, overAppliedCalculationType, overAppliedNumber, dueDaysForRepaymentEvent,
|
||||||
|
overDueDaysForRepaymentEvent);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -599,7 +610,7 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
final boolean syncExpectedWithDisbursementDate, final boolean canUseForTopup, final boolean isEqualAmortization,
|
final boolean syncExpectedWithDisbursementDate, final boolean canUseForTopup, final boolean isEqualAmortization,
|
||||||
final List<Rate> rates, final BigDecimal fixedPrincipalPercentagePerInstallment, final boolean disallowExpectedDisbursements,
|
final List<Rate> rates, final BigDecimal fixedPrincipalPercentagePerInstallment, final boolean disallowExpectedDisbursements,
|
||||||
final boolean allowApprovedDisbursedAmountsOverApplied, final String overAppliedCalculationType,
|
final boolean allowApprovedDisbursedAmountsOverApplied, final String overAppliedCalculationType,
|
||||||
final Integer overAppliedNumber) {
|
final Integer overAppliedNumber, final Integer dueDaysForRepaymentEvent, final Integer overDueDaysForRepaymentEvent) {
|
||||||
this.fund = fund;
|
this.fund = fund;
|
||||||
this.transactionProcessingStrategyCode = transactionProcessingStrategyCode;
|
this.transactionProcessingStrategyCode = transactionProcessingStrategyCode;
|
||||||
this.name = name.trim();
|
this.name = name.trim();
|
||||||
@@ -681,6 +692,10 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
if (rates != null) {
|
if (rates != null) {
|
||||||
this.rates = rates;
|
this.rates = rates;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.dueDaysForRepaymentEvent = dueDaysForRepaymentEvent;
|
||||||
|
this.overDueDaysForRepaymentEvent = overDueDaysForRepaymentEvent;
|
||||||
|
|
||||||
validateLoanProductPreSave();
|
validateLoanProductPreSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1184,6 +1199,21 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
this.overAppliedNumber = newValue;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
return actualChanges;
|
return actualChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1571,4 +1601,12 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
this.delinquencyBucket = delinquencyBucket;
|
this.delinquencyBucket = delinquencyBucket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Integer getDueDaysForRepaymentEvent() {
|
||||||
|
return this.dueDaysForRepaymentEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getOverDueDaysForRepaymentEvent() {
|
||||||
|
return this.overDueDaysForRepaymentEvent;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-1
@@ -158,7 +158,8 @@ public final class LoanProductDataValidator {
|
|||||||
LoanProductConstants.CAN_USE_FOR_TOPUP, LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM, LoanProductConstants.RATES_PARAM_NAME,
|
LoanProductConstants.CAN_USE_FOR_TOPUP, LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM, LoanProductConstants.RATES_PARAM_NAME,
|
||||||
LoanProductConstants.fixedPrincipalPercentagePerInstallmentParamName, LoanProductConstants.DISALLOW_EXPECTED_DISBURSEMENTS,
|
LoanProductConstants.fixedPrincipalPercentagePerInstallmentParamName, LoanProductConstants.DISALLOW_EXPECTED_DISBURSEMENTS,
|
||||||
LoanProductConstants.ALLOW_APPROVED_DISBURSED_AMOUNTS_OVER_APPLIED, LoanProductConstants.OVER_APPLIED_CALCULATION_TYPE,
|
LoanProductConstants.ALLOW_APPROVED_DISBURSED_AMOUNTS_OVER_APPLIED, LoanProductConstants.OVER_APPLIED_CALCULATION_TYPE,
|
||||||
LoanProductConstants.OVER_APPLIED_NUMBER, LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME));
|
LoanProductConstants.OVER_APPLIED_NUMBER, LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME,
|
||||||
|
LoanProductConstants.DUE_DAYS_FOR_REPAYMENT_EVENT, LoanProductConstants.OVER_DUE_DAYS_FOR_REPAYMENT_EVENT));
|
||||||
|
|
||||||
private static final String[] SUPPORTED_LOAN_CONFIGURABLE_ATTRIBUTES = { LoanProductConstants.amortizationTypeParamName,
|
private static final String[] SUPPORTED_LOAN_CONFIGURABLE_ATTRIBUTES = { LoanProductConstants.amortizationTypeParamName,
|
||||||
LoanProductConstants.interestTypeParamName, LoanProductConstants.transactionProcessingStrategyCodeParamName,
|
LoanProductConstants.interestTypeParamName, LoanProductConstants.transactionProcessingStrategyCodeParamName,
|
||||||
@@ -733,6 +734,16 @@ public final class LoanProductDataValidator {
|
|||||||
baseDataValidator.reset().parameter(LoanProductConstants.CAN_USE_FOR_TOPUP).value(canUseForTopup).validateForBooleanValue();
|
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();
|
||||||
|
|
||||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1600,6 +1611,16 @@ public final class LoanProductDataValidator {
|
|||||||
baseDataValidator.reset().parameter(LoanProductConstants.CAN_USE_FOR_TOPUP).value(canUseForTopup).validateForBooleanValue();
|
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();
|
||||||
|
|
||||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-1
@@ -216,6 +216,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
|||||||
+ "lp.disallow_expected_disbursements as disallowExpectedDisbursements, lp.allow_approved_disbursed_amounts_over_applied as allowApprovedDisbursedAmountsOverApplied, lp.over_applied_calculation_type as overAppliedCalculationType, over_applied_number as overAppliedNumber, "
|
+ "lp.disallow_expected_disbursements as disallowExpectedDisbursements, lp.allow_approved_disbursed_amounts_over_applied as allowApprovedDisbursedAmountsOverApplied, lp.over_applied_calculation_type as overAppliedCalculationType, over_applied_number as overAppliedNumber, "
|
||||||
+ "lp.days_in_month_enum as daysInMonth, lp.days_in_year_enum as daysInYear, lp.interest_recalculation_enabled as isInterestRecalculationEnabled, "
|
+ "lp.days_in_month_enum as daysInMonth, lp.days_in_year_enum as daysInYear, lp.interest_recalculation_enabled as isInterestRecalculationEnabled, "
|
||||||
+ "lp.can_define_fixed_emi_amount as canDefineInstallmentAmount, lp.instalment_amount_in_multiples_of as installmentAmountInMultiplesOf, "
|
+ "lp.can_define_fixed_emi_amount as canDefineInstallmentAmount, lp.instalment_amount_in_multiples_of as installmentAmountInMultiplesOf, "
|
||||||
|
+ "lp.due_days_for_repayment_event as dueDaysForRepaymentEvent, lp.overdue_days_for_repayment_event as overDueDaysForRepaymentEvent,"
|
||||||
+ "lpr.pre_close_interest_calculation_strategy as preCloseInterestCalculationStrategy, "
|
+ "lpr.pre_close_interest_calculation_strategy as preCloseInterestCalculationStrategy, "
|
||||||
+ "lpr.id as lprId, lpr.product_id as productId, lpr.compound_type_enum as compoundType, lpr.reschedule_strategy_enum as rescheduleStrategy, "
|
+ "lpr.id as lprId, lpr.product_id as productId, lpr.compound_type_enum as compoundType, lpr.reschedule_strategy_enum as rescheduleStrategy, "
|
||||||
+ "lpr.rest_frequency_type_enum as restFrequencyEnum, lpr.rest_frequency_interval as restFrequencyInterval, "
|
+ "lpr.rest_frequency_type_enum as restFrequencyEnum, lpr.rest_frequency_interval as restFrequencyInterval, "
|
||||||
@@ -345,6 +346,8 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
|||||||
final boolean useBorrowerCycle = rs.getBoolean("useBorrowerCycle");
|
final boolean useBorrowerCycle = rs.getBoolean("useBorrowerCycle");
|
||||||
final LocalDate startDate = JdbcSupport.getLocalDate(rs, "startDate");
|
final LocalDate startDate = JdbcSupport.getLocalDate(rs, "startDate");
|
||||||
final LocalDate closeDate = JdbcSupport.getLocalDate(rs, "closeDate");
|
final LocalDate closeDate = JdbcSupport.getLocalDate(rs, "closeDate");
|
||||||
|
final Integer dueDaysForRepaymentEvent = JdbcSupport.getIntegerDefaultToNullIfZero(rs, "dueDaysForRepaymentEvent");
|
||||||
|
final Integer overDueDaysForRepaymentEvent = JdbcSupport.getIntegerDefaultToNullIfZero(rs, "overDueDaysForRepaymentEvent");
|
||||||
String status = "";
|
String status = "";
|
||||||
if (closeDate != null && closeDate.isBefore(DateUtils.getBusinessLocalDate())) {
|
if (closeDate != null && closeDate.isBefore(DateUtils.getBusinessLocalDate())) {
|
||||||
status = "loanProduct.inActive";
|
status = "loanProduct.inActive";
|
||||||
@@ -499,7 +502,8 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
|||||||
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
||||||
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableIntallmentsAllowed, minimumGap,
|
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableIntallmentsAllowed, minimumGap,
|
||||||
maximumGap, syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, this.rates,
|
maximumGap, syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, this.rates,
|
||||||
isRatesEnabled, fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket);
|
isRatesEnabled, fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket,
|
||||||
|
dueDaysForRepaymentEvent, overDueDaysForRepaymentEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -123,4 +123,5 @@
|
|||||||
<include file="parts/0101_update_transaction_summary_table_report.xml" relativeToChangelogFile="true" />
|
<include file="parts/0101_update_transaction_summary_table_report.xml" relativeToChangelogFile="true" />
|
||||||
<include file="parts/0102_add_external_event_for_loan_reschedule.xml" relativeToChangelogFile="true" />
|
<include file="parts/0102_add_external_event_for_loan_reschedule.xml" relativeToChangelogFile="true" />
|
||||||
<include file="parts/0103_modify_parameter_json_column_custom_job_parameters.xml" relativeToChangelogFile="true" />
|
<include file="parts/0103_modify_parameter_json_column_custom_job_parameters.xml" relativeToChangelogFile="true" />
|
||||||
|
<include file="parts/0104_loan_product_add_repayment_overdue_days_config.xml" relativeToChangelogFile="true" />
|
||||||
</databaseChangeLog>
|
</databaseChangeLog>
|
||||||
|
|||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
|
||||||
|
<changeSet author="fineract" id="1">
|
||||||
|
<addColumn tableName="m_product_loan">
|
||||||
|
<column name="due_days_for_repayment_event" type="INT">
|
||||||
|
<constraints nullable="true"/>
|
||||||
|
</column>
|
||||||
|
</addColumn>
|
||||||
|
<addColumn tableName="m_product_loan">
|
||||||
|
<column name="overdue_days_for_repayment_event" type="INT">
|
||||||
|
<constraints nullable="true"/>
|
||||||
|
</column>
|
||||||
|
</addColumn>
|
||||||
|
</changeSet>
|
||||||
|
</databaseChangeLog>
|
||||||
+35
@@ -42,6 +42,7 @@ import org.apache.fineract.infrastructure.event.business.domain.loan.repayment.L
|
|||||||
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
@@ -75,10 +76,13 @@ public class CheckLoanRepaymentDueBusinessStepTest {
|
|||||||
when(configurationDomainService.retrieveRepaymentDueDays()).thenReturn(1L);
|
when(configurationDomainService.retrieveRepaymentDueDays()).thenReturn(1L);
|
||||||
LocalDate loanInstallmentRepaymentDueDate = DateUtils.getBusinessLocalDate().plusDays(1);
|
LocalDate loanInstallmentRepaymentDueDate = DateUtils.getBusinessLocalDate().plusDays(1);
|
||||||
Loan loanForProcessing = Mockito.mock(Loan.class);
|
Loan loanForProcessing = Mockito.mock(Loan.class);
|
||||||
|
LoanProduct loanProduct = Mockito.mock(LoanProduct.class);
|
||||||
LoanRepaymentScheduleInstallment repaymentInstallment = new LoanRepaymentScheduleInstallment(loanForProcessing, 1,
|
LoanRepaymentScheduleInstallment repaymentInstallment = new LoanRepaymentScheduleInstallment(loanForProcessing, 1,
|
||||||
LocalDate.now(ZoneId.systemDefault()), loanInstallmentRepaymentDueDate, BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0),
|
LocalDate.now(ZoneId.systemDefault()), loanInstallmentRepaymentDueDate, BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0),
|
||||||
BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), false, new HashSet<>(), BigDecimal.valueOf(0.0));
|
BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), false, new HashSet<>(), BigDecimal.valueOf(0.0));
|
||||||
List<LoanRepaymentScheduleInstallment> loanRepaymentScheduleInstallments = Arrays.asList(repaymentInstallment);
|
List<LoanRepaymentScheduleInstallment> loanRepaymentScheduleInstallments = Arrays.asList(repaymentInstallment);
|
||||||
|
when(loanForProcessing.getLoanProduct()).thenReturn(loanProduct);
|
||||||
|
when(loanProduct.getDueDaysForRepaymentEvent()).thenReturn(null);
|
||||||
when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(loanRepaymentScheduleInstallments);
|
when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(loanRepaymentScheduleInstallments);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@@ -97,10 +101,13 @@ public class CheckLoanRepaymentDueBusinessStepTest {
|
|||||||
when(configurationDomainService.retrieveRepaymentDueDays()).thenReturn(1L);
|
when(configurationDomainService.retrieveRepaymentDueDays()).thenReturn(1L);
|
||||||
LocalDate loanInstallmentRepaymentDueDateAfter5Days = DateUtils.getBusinessLocalDate().plusDays(5);
|
LocalDate loanInstallmentRepaymentDueDateAfter5Days = DateUtils.getBusinessLocalDate().plusDays(5);
|
||||||
Loan loanForProcessing = Mockito.mock(Loan.class);
|
Loan loanForProcessing = Mockito.mock(Loan.class);
|
||||||
|
LoanProduct loanProduct = Mockito.mock(LoanProduct.class);
|
||||||
List<LoanRepaymentScheduleInstallment> loanRepaymentScheduleInstallments = Arrays
|
List<LoanRepaymentScheduleInstallment> loanRepaymentScheduleInstallments = Arrays
|
||||||
.asList(new LoanRepaymentScheduleInstallment(loanForProcessing, 1, LocalDate.now(ZoneId.systemDefault()),
|
.asList(new LoanRepaymentScheduleInstallment(loanForProcessing, 1, LocalDate.now(ZoneId.systemDefault()),
|
||||||
loanInstallmentRepaymentDueDateAfter5Days, BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0),
|
loanInstallmentRepaymentDueDateAfter5Days, BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0),
|
||||||
BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), false, new HashSet<>(), BigDecimal.valueOf(0.0)));
|
BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), false, new HashSet<>(), BigDecimal.valueOf(0.0)));
|
||||||
|
when(loanForProcessing.getLoanProduct()).thenReturn(loanProduct);
|
||||||
|
when(loanProduct.getDueDaysForRepaymentEvent()).thenReturn(null);
|
||||||
when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(loanRepaymentScheduleInstallments);
|
when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(loanRepaymentScheduleInstallments);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@@ -110,4 +117,32 @@ public class CheckLoanRepaymentDueBusinessStepTest {
|
|||||||
assertEquals(processedLoan, loanForProcessing);
|
assertEquals(processedLoan, loanForProcessing);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenLoanWithInstallmentDueAfterConfiguredDaysInLoanProductWhenStepExecutionThenBusinessEventIsRaised() {
|
||||||
|
ArgumentCaptor<LoanRepaymentDueBusinessEvent> loanRepaymentDueEvent = ArgumentCaptor.forClass(LoanRepaymentDueBusinessEvent.class);
|
||||||
|
// given
|
||||||
|
// Global config settings
|
||||||
|
when(configurationDomainService.retrieveRepaymentDueDays()).thenReturn(2L);
|
||||||
|
LocalDate loanInstallmentRepaymentDueDate = DateUtils.getBusinessLocalDate().plusDays(1);
|
||||||
|
Loan loanForProcessing = Mockito.mock(Loan.class);
|
||||||
|
LoanProduct loanProduct = Mockito.mock(LoanProduct.class);
|
||||||
|
LoanRepaymentScheduleInstallment repaymentInstallment = new LoanRepaymentScheduleInstallment(loanForProcessing, 1,
|
||||||
|
LocalDate.now(ZoneId.systemDefault()), loanInstallmentRepaymentDueDate, BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0),
|
||||||
|
BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), false, new HashSet<>(), BigDecimal.valueOf(0.0));
|
||||||
|
List<LoanRepaymentScheduleInstallment> loanRepaymentScheduleInstallments = Arrays.asList(repaymentInstallment);
|
||||||
|
when(loanForProcessing.getLoanProduct()).thenReturn(loanProduct);
|
||||||
|
// Loan Product setting overrides global settings
|
||||||
|
when(loanProduct.getDueDaysForRepaymentEvent()).thenReturn(1);
|
||||||
|
when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(loanRepaymentScheduleInstallments);
|
||||||
|
|
||||||
|
// when
|
||||||
|
Loan processedLoan = underTest.execute(loanForProcessing);
|
||||||
|
// then
|
||||||
|
verify(businessEventNotifierService, times(1)).notifyPostBusinessEvent(loanRepaymentDueEvent.capture());
|
||||||
|
LoanRepaymentScheduleInstallment loanPayloadForEvent = loanRepaymentDueEvent.getValue().get();
|
||||||
|
assertEquals(repaymentInstallment, loanPayloadForEvent);
|
||||||
|
assertEquals(processedLoan, loanForProcessing);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+38
@@ -42,6 +42,7 @@ import org.apache.fineract.infrastructure.event.business.domain.loan.repayment.L
|
|||||||
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
@@ -76,10 +77,13 @@ public class CheckLoanRepaymentOverdueBusinessStepTest {
|
|||||||
when(configurationDomainService.retrieveRepaymentOverdueDays()).thenReturn(1L);
|
when(configurationDomainService.retrieveRepaymentOverdueDays()).thenReturn(1L);
|
||||||
LocalDate loanInstallmentRepaymentDueDate = DateUtils.getBusinessLocalDate().minusDays(1);
|
LocalDate loanInstallmentRepaymentDueDate = DateUtils.getBusinessLocalDate().minusDays(1);
|
||||||
Loan loanForProcessing = Mockito.mock(Loan.class);
|
Loan loanForProcessing = Mockito.mock(Loan.class);
|
||||||
|
LoanProduct loanProduct = Mockito.mock(LoanProduct.class);
|
||||||
LoanRepaymentScheduleInstallment repaymentInstallment = new LoanRepaymentScheduleInstallment(loanForProcessing, 1,
|
LoanRepaymentScheduleInstallment repaymentInstallment = new LoanRepaymentScheduleInstallment(loanForProcessing, 1,
|
||||||
LocalDate.now(ZoneId.systemDefault()), loanInstallmentRepaymentDueDate, BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0),
|
LocalDate.now(ZoneId.systemDefault()), loanInstallmentRepaymentDueDate, BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0),
|
||||||
BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), false, new HashSet<>(), BigDecimal.valueOf(0.0));
|
BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), false, new HashSet<>(), BigDecimal.valueOf(0.0));
|
||||||
List<LoanRepaymentScheduleInstallment> loanRepaymentScheduleInstallments = Arrays.asList(repaymentInstallment);
|
List<LoanRepaymentScheduleInstallment> loanRepaymentScheduleInstallments = Arrays.asList(repaymentInstallment);
|
||||||
|
when(loanForProcessing.getLoanProduct()).thenReturn(loanProduct);
|
||||||
|
when(loanProduct.getOverDueDaysForRepaymentEvent()).thenReturn(null);
|
||||||
when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(loanRepaymentScheduleInstallments);
|
when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(loanRepaymentScheduleInstallments);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@@ -97,10 +101,13 @@ public class CheckLoanRepaymentOverdueBusinessStepTest {
|
|||||||
when(configurationDomainService.retrieveRepaymentOverdueDays()).thenReturn(1L);
|
when(configurationDomainService.retrieveRepaymentOverdueDays()).thenReturn(1L);
|
||||||
LocalDate loanInstallmentRepaymentDueDateBefore5Days = DateUtils.getBusinessLocalDate().minusDays(5);
|
LocalDate loanInstallmentRepaymentDueDateBefore5Days = DateUtils.getBusinessLocalDate().minusDays(5);
|
||||||
Loan loanForProcessing = Mockito.mock(Loan.class);
|
Loan loanForProcessing = Mockito.mock(Loan.class);
|
||||||
|
LoanProduct loanProduct = Mockito.mock(LoanProduct.class);
|
||||||
List<LoanRepaymentScheduleInstallment> loanRepaymentScheduleInstallments = Arrays
|
List<LoanRepaymentScheduleInstallment> loanRepaymentScheduleInstallments = Arrays
|
||||||
.asList(new LoanRepaymentScheduleInstallment(loanForProcessing, 1, LocalDate.now(ZoneId.systemDefault()),
|
.asList(new LoanRepaymentScheduleInstallment(loanForProcessing, 1, LocalDate.now(ZoneId.systemDefault()),
|
||||||
loanInstallmentRepaymentDueDateBefore5Days, BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0),
|
loanInstallmentRepaymentDueDateBefore5Days, BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0),
|
||||||
BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), false, new HashSet<>(), BigDecimal.valueOf(0.0)));
|
BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), false, new HashSet<>(), BigDecimal.valueOf(0.0)));
|
||||||
|
when(loanForProcessing.getLoanProduct()).thenReturn(loanProduct);
|
||||||
|
when(loanProduct.getOverDueDaysForRepaymentEvent()).thenReturn(null);
|
||||||
when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(loanRepaymentScheduleInstallments);
|
when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(loanRepaymentScheduleInstallments);
|
||||||
// when
|
// when
|
||||||
Loan processedLoan = underTest.execute(loanForProcessing);
|
Loan processedLoan = underTest.execute(loanForProcessing);
|
||||||
@@ -116,6 +123,7 @@ public class CheckLoanRepaymentOverdueBusinessStepTest {
|
|||||||
when(configurationDomainService.retrieveRepaymentOverdueDays()).thenReturn(1L);
|
when(configurationDomainService.retrieveRepaymentOverdueDays()).thenReturn(1L);
|
||||||
LocalDate loanInstallmentRepaymentDueDate = DateUtils.getBusinessLocalDate().minusDays(1);
|
LocalDate loanInstallmentRepaymentDueDate = DateUtils.getBusinessLocalDate().minusDays(1);
|
||||||
Loan loanForProcessing = Mockito.mock(Loan.class);
|
Loan loanForProcessing = Mockito.mock(Loan.class);
|
||||||
|
LoanProduct loanProduct = Mockito.mock(LoanProduct.class);
|
||||||
LoanRepaymentScheduleInstallment repaymentInstallmentPaidOff = new LoanRepaymentScheduleInstallment(loanForProcessing, 1,
|
LoanRepaymentScheduleInstallment repaymentInstallmentPaidOff = new LoanRepaymentScheduleInstallment(loanForProcessing, 1,
|
||||||
LocalDate.now(ZoneId.systemDefault()), loanInstallmentRepaymentDueDate, BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0),
|
LocalDate.now(ZoneId.systemDefault()), loanInstallmentRepaymentDueDate, BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0),
|
||||||
BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), false, new HashSet<>(), BigDecimal.valueOf(0.0));
|
BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), false, new HashSet<>(), BigDecimal.valueOf(0.0));
|
||||||
@@ -123,6 +131,8 @@ public class CheckLoanRepaymentOverdueBusinessStepTest {
|
|||||||
repaymentInstallmentPaidOff.updateObligationMet(true);
|
repaymentInstallmentPaidOff.updateObligationMet(true);
|
||||||
|
|
||||||
List<LoanRepaymentScheduleInstallment> loanRepaymentScheduleInstallments = Arrays.asList(repaymentInstallmentPaidOff);
|
List<LoanRepaymentScheduleInstallment> loanRepaymentScheduleInstallments = Arrays.asList(repaymentInstallmentPaidOff);
|
||||||
|
when(loanForProcessing.getLoanProduct()).thenReturn(loanProduct);
|
||||||
|
when(loanProduct.getOverDueDaysForRepaymentEvent()).thenReturn(null);
|
||||||
when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(loanRepaymentScheduleInstallments);
|
when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(loanRepaymentScheduleInstallments);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@@ -132,4 +142,32 @@ public class CheckLoanRepaymentOverdueBusinessStepTest {
|
|||||||
assertEquals(processedLoan, loanForProcessing);
|
assertEquals(processedLoan, loanForProcessing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenLoanWithInstallmentOverdueAfterConfiguredDaysInLoanProductWhenStepExecutionThenBusinessEventIsRaised() {
|
||||||
|
ArgumentCaptor<LoanRepaymentOverdueBusinessEvent> loanRepaymentDueBusinessEventArgumentCaptor = ArgumentCaptor
|
||||||
|
.forClass(LoanRepaymentOverdueBusinessEvent.class);
|
||||||
|
// given
|
||||||
|
// global configuration
|
||||||
|
when(configurationDomainService.retrieveRepaymentOverdueDays()).thenReturn(2L);
|
||||||
|
LocalDate loanInstallmentRepaymentDueDate = DateUtils.getBusinessLocalDate().minusDays(1);
|
||||||
|
Loan loanForProcessing = Mockito.mock(Loan.class);
|
||||||
|
LoanProduct loanProduct = Mockito.mock(LoanProduct.class);
|
||||||
|
LoanRepaymentScheduleInstallment repaymentInstallment = new LoanRepaymentScheduleInstallment(loanForProcessing, 1,
|
||||||
|
LocalDate.now(ZoneId.systemDefault()), loanInstallmentRepaymentDueDate, BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0),
|
||||||
|
BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), false, new HashSet<>(), BigDecimal.valueOf(0.0));
|
||||||
|
List<LoanRepaymentScheduleInstallment> loanRepaymentScheduleInstallments = Arrays.asList(repaymentInstallment);
|
||||||
|
when(loanForProcessing.getLoanProduct()).thenReturn(loanProduct);
|
||||||
|
// product configuration overrides global configuration
|
||||||
|
when(loanProduct.getOverDueDaysForRepaymentEvent()).thenReturn(1);
|
||||||
|
when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(loanRepaymentScheduleInstallments);
|
||||||
|
|
||||||
|
// when
|
||||||
|
Loan processedLoan = underTest.execute(loanForProcessing);
|
||||||
|
// then
|
||||||
|
verify(businessEventNotifierService, times(1)).notifyPostBusinessEvent(loanRepaymentDueBusinessEventArgumentCaptor.capture());
|
||||||
|
LoanRepaymentScheduleInstallment loanPayloadForEvent = loanRepaymentDueBusinessEventArgumentCaptor.getValue().get();
|
||||||
|
assertEquals(repaymentInstallment, loanPayloadForEvent);
|
||||||
|
assertEquals(processedLoan, loanForProcessing);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+135
@@ -0,0 +1,135 @@
|
|||||||
|
/**
|
||||||
|
* 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.integrationtests;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
|
import io.restassured.builder.RequestSpecBuilder;
|
||||||
|
import io.restassured.builder.ResponseSpecBuilder;
|
||||||
|
import io.restassured.http.ContentType;
|
||||||
|
import io.restassured.specification.RequestSpecification;
|
||||||
|
import io.restassured.specification.ResponseSpecification;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.UUID;
|
||||||
|
import org.apache.fineract.client.models.GetDelinquencyBucketsResponse;
|
||||||
|
import org.apache.fineract.client.models.GetLoanProductsProductIdResponse;
|
||||||
|
import org.apache.fineract.client.models.PutLoanProductsProductIdRequest;
|
||||||
|
import org.apache.fineract.client.models.PutLoanProductsProductIdResponse;
|
||||||
|
import org.apache.fineract.integrationtests.common.ClientHelper;
|
||||||
|
import org.apache.fineract.integrationtests.common.Utils;
|
||||||
|
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
|
||||||
|
import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
|
||||||
|
import org.apache.fineract.integrationtests.common.products.DelinquencyBucketsHelper;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
public class LoanProductWithRepaymentDueEventConfigurationTest {
|
||||||
|
|
||||||
|
private ResponseSpecification responseSpec;
|
||||||
|
private RequestSpecification requestSpec;
|
||||||
|
private ClientHelper clientHelper;
|
||||||
|
private LoanTransactionHelper loanTransactionHelper;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setup() {
|
||||||
|
Utils.initializeRESTAssured();
|
||||||
|
this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
|
||||||
|
this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
|
||||||
|
this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
|
||||||
|
this.clientHelper = new ClientHelper(this.requestSpec, this.responseSpec);
|
||||||
|
this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loanProductCreationWithDueDaysConfigurationForRepaymentEventTest() {
|
||||||
|
// Loan ExternalId
|
||||||
|
String loanExternalIdStr = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
// Delinquency Bucket
|
||||||
|
final Integer delinquencyBucketId = DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec, responseSpec);
|
||||||
|
final GetDelinquencyBucketsResponse delinquencyBucket = DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec,
|
||||||
|
delinquencyBucketId);
|
||||||
|
|
||||||
|
// event days configuration
|
||||||
|
Integer dueDaysForRepaymentEvent = 1;
|
||||||
|
Integer overDueDaysForRepaymentEvent = 2;
|
||||||
|
|
||||||
|
// Client and Loan account creation
|
||||||
|
|
||||||
|
final Integer clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue();
|
||||||
|
Integer loanProductId = createLoanProductWithDueDaysForRepaymentEvent(loanTransactionHelper, delinquencyBucketId,
|
||||||
|
dueDaysForRepaymentEvent, overDueDaysForRepaymentEvent);
|
||||||
|
final GetLoanProductsProductIdResponse getLoanProductsProductResponse = loanTransactionHelper.getLoanProduct(loanProductId);
|
||||||
|
assertNotNull(getLoanProductsProductResponse);
|
||||||
|
assertNotNull(getLoanProductsProductResponse.getDueDaysForRepaymentEvent());
|
||||||
|
assertNotNull(getLoanProductsProductResponse.getOverDueDaysForRepaymentEvent());
|
||||||
|
assertEquals(getLoanProductsProductResponse.getDueDaysForRepaymentEvent(), dueDaysForRepaymentEvent);
|
||||||
|
assertEquals(getLoanProductsProductResponse.getOverDueDaysForRepaymentEvent(), overDueDaysForRepaymentEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loanProductUpdateWithDueDaysConfigurationForRepaymentEventTest() {
|
||||||
|
// Loan ExternalId
|
||||||
|
String loanExternalIdStr = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
// Delinquency Bucket
|
||||||
|
final Integer delinquencyBucketId = DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec, responseSpec);
|
||||||
|
final GetDelinquencyBucketsResponse delinquencyBucket = DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec,
|
||||||
|
delinquencyBucketId);
|
||||||
|
|
||||||
|
// Client and Loan account creation
|
||||||
|
|
||||||
|
final Integer clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue();
|
||||||
|
final GetLoanProductsProductIdResponse getLoanProductsProductResponse = createLoanProduct(loanTransactionHelper,
|
||||||
|
delinquencyBucketId);
|
||||||
|
assertNotNull(getLoanProductsProductResponse);
|
||||||
|
|
||||||
|
// Modify Loan Product
|
||||||
|
PutLoanProductsProductIdResponse loanProductModifyResponse = updateLoanProduct(loanTransactionHelper,
|
||||||
|
getLoanProductsProductResponse.getId());
|
||||||
|
assertNotNull(loanProductModifyResponse);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private PutLoanProductsProductIdResponse updateLoanProduct(LoanTransactionHelper loanTransactionHelper, Long id) {
|
||||||
|
// event days configuration
|
||||||
|
Integer dueDaysForRepaymentEvent = 1;
|
||||||
|
Integer overDueDaysForRepaymentEvent = 2;
|
||||||
|
final PutLoanProductsProductIdRequest requestModifyLoan = new PutLoanProductsProductIdRequest()
|
||||||
|
.dueDaysForRepaymentEvent(dueDaysForRepaymentEvent).overDueDaysForRepaymentEvent(overDueDaysForRepaymentEvent).locale("en");
|
||||||
|
return loanTransactionHelper.updateLoanProduct(id, requestModifyLoan);
|
||||||
|
}
|
||||||
|
|
||||||
|
private GetLoanProductsProductIdResponse createLoanProduct(final LoanTransactionHelper loanTransactionHelper,
|
||||||
|
final Integer delinquencyBucketId) {
|
||||||
|
final HashMap<String, Object> loanProductMap = new LoanProductTestBuilder().build(null, delinquencyBucketId);
|
||||||
|
final Integer loanProductId = loanTransactionHelper.getLoanProductId(Utils.convertToJson(loanProductMap));
|
||||||
|
return loanTransactionHelper.getLoanProduct(loanProductId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer createLoanProductWithDueDaysForRepaymentEvent(final LoanTransactionHelper loanTransactionHelper,
|
||||||
|
final Integer delinquencyBucketId, Integer dueDaysForRepaymentEvent, Integer overDueDaysForRepaymentEvent) {
|
||||||
|
final HashMap<String, Object> loanProductMap = new LoanProductTestBuilder().withDueDaysForRepaymentEvent(dueDaysForRepaymentEvent)
|
||||||
|
.withOverDueDaysForRepaymentEvent(overDueDaysForRepaymentEvent).build(null, delinquencyBucketId);
|
||||||
|
final Integer loanProductId = loanTransactionHelper.getLoanProductId(Utils.convertToJson(loanProductMap));
|
||||||
|
return loanProductId;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+20
@@ -138,6 +138,8 @@ public class LoanProductTestBuilder {
|
|||||||
private String installmentAmountInMultiplesOf;
|
private String installmentAmountInMultiplesOf;
|
||||||
private boolean canDefineInstallmentAmount;
|
private boolean canDefineInstallmentAmount;
|
||||||
private Integer delinquencyBucketId;
|
private Integer delinquencyBucketId;
|
||||||
|
private Integer dueDaysForRepaymentEvent = null;
|
||||||
|
private Integer overDueDaysForRepaymentEvent = null;
|
||||||
|
|
||||||
public String build(final String chargeId) {
|
public String build(final String chargeId) {
|
||||||
final HashMap<String, Object> map = build(chargeId, null);
|
final HashMap<String, Object> map = build(chargeId, null);
|
||||||
@@ -267,6 +269,13 @@ public class LoanProductTestBuilder {
|
|||||||
map.put("penaltyToIncomeAccountMappings", this.penaltyToIncomeAccountMappings);
|
map.put("penaltyToIncomeAccountMappings", this.penaltyToIncomeAccountMappings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.dueDaysForRepaymentEvent != null) {
|
||||||
|
map.put("dueDaysForRepaymentEvent", this.dueDaysForRepaymentEvent);
|
||||||
|
}
|
||||||
|
if (this.overDueDaysForRepaymentEvent != null) {
|
||||||
|
map.put("overDueDaysForRepaymentEvent", this.overDueDaysForRepaymentEvent);
|
||||||
|
}
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -656,4 +665,15 @@ public class LoanProductTestBuilder {
|
|||||||
this.feeAndPenaltyAssetAccount = account;
|
this.feeAndPenaltyAssetAccount = account;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LoanProductTestBuilder withDueDaysForRepaymentEvent(final Integer dueDaysForRepaymentEvent) {
|
||||||
|
this.dueDaysForRepaymentEvent = dueDaysForRepaymentEvent;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoanProductTestBuilder withOverDueDaysForRepaymentEvent(final Integer overDueDaysForRepaymentEvent) {
|
||||||
|
this.overDueDaysForRepaymentEvent = overDueDaysForRepaymentEvent;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+6
@@ -70,6 +70,8 @@ import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
|
|||||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsTransactionIdRequest;
|
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsTransactionIdRequest;
|
||||||
import org.apache.fineract.client.models.PutChargeTransactionChangesRequest;
|
import org.apache.fineract.client.models.PutChargeTransactionChangesRequest;
|
||||||
import org.apache.fineract.client.models.PutChargeTransactionChangesResponse;
|
import org.apache.fineract.client.models.PutChargeTransactionChangesResponse;
|
||||||
|
import org.apache.fineract.client.models.PutLoanProductsProductIdRequest;
|
||||||
|
import org.apache.fineract.client.models.PutLoanProductsProductIdResponse;
|
||||||
import org.apache.fineract.client.models.PutLoansLoanIdChargesChargeIdRequest;
|
import org.apache.fineract.client.models.PutLoansLoanIdChargesChargeIdRequest;
|
||||||
import org.apache.fineract.client.models.PutLoansLoanIdChargesChargeIdResponse;
|
import org.apache.fineract.client.models.PutLoansLoanIdChargesChargeIdResponse;
|
||||||
import org.apache.fineract.client.models.PutLoansLoanIdRequest;
|
import org.apache.fineract.client.models.PutLoansLoanIdRequest;
|
||||||
@@ -1844,4 +1846,8 @@ public class LoanTransactionHelper extends IntegrationTest {
|
|||||||
final String get = Utils.performServerGet(requestSpec, responseSpec, GET_LOAN_URL, null);
|
final String get = Utils.performServerGet(requestSpec, responseSpec, GET_LOAN_URL, null);
|
||||||
return new Gson().fromJson(get, new TypeToken<ArrayList<Integer>>() {}.getType());
|
return new Gson().fromJson(get, new TypeToken<ArrayList<Integer>>() {}.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PutLoanProductsProductIdResponse updateLoanProduct(Long id, PutLoanProductsProductIdRequest requestModifyLoan) {
|
||||||
|
return ok(fineract().loanProducts.updateLoanProduct(id, requestModifyLoan));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user