Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,14 @@
"boolean"
]
},
{
"default": null,
"name": "repaymentStartDateType",
"type": [
"null",
"org.apache.fineract.avro.generic.v1.EnumOptionDataV1"
]
},
{
"default": null,
"name": "interestRecognitionOnDisbursementDate",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,13 @@ public static String wrongfixedLength(Integer actual, Integer expected) {
expectedToStr);
}

public static String wrongRepaymentStartDateType(final Integer actual, final Integer expected) {
final String actualToStr = actual.toString();
final String expectedToStr = expected.toString();
return String.format("Wrong value in LoanDetails/repaymentStartDateType. %nActual value is: %s %nExpected Value is: %s",
actualToStr, expectedToStr);
}

public static String downpaymentDisabledOnProductErrorCodeMsg() {
return "The Loan can not override the downpayment properties because in the Loan Product the downpayment is disabled";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3470,6 +3470,20 @@ public void checkLoanDetailsFieldAndValueInt(int fieldValue) throws NoSuchMethod
assertThat(fixedLengthactual).as(ErrorMessageHelper.wrongfixedLength(fixedLengthactual, fieldValue)).isEqualTo(fieldValue);
}

@Then("LoanDetails has repaymentStartDateType field with value: {string}")
public void checkLoanDetailsRepaymentStartDateTypeField(final String expectedType) {
final PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
final long loanId = loanResponse.getLoanId();

final GetLoansLoanIdResponse loanDetails = ok(
() -> fineractClient.loans().retrieveLoan(loanId, Map.of("staffInSelectedOfficeOnly", "false")));
assert loanDetails.getRepaymentStartDateType() != null;
assert loanDetails.getRepaymentStartDateType().getId() != null;
final Integer actualValue = loanDetails.getRepaymentStartDateType().getId().intValue();
final Integer expectedValue = RepaymentStartDateType.valueOf(expectedType).getValue();
assertThat(actualValue).as(ErrorMessageHelper.wrongRepaymentStartDateType(actualValue, expectedValue)).isEqualTo(expectedValue);
}

@Then("Loan has availableDisbursementAmountWithOverApplied field with value: {double}")
public void checkLoanDetailsAvailableDisbursementAmountWithOverAppliedField(final double fieldValue) {
final PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ Feature: LoanRepayment - Part4
When Admin creates a fully customized loan with the following data:
| LoanProduct | submitted on date | expected disbursement date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | Repayment start date type |
| LP2_ADV_PYMNT_ZERO_INTEREST_CHARGE_OFF_BEHAVIOUR | 31 January 2024 | 10 February 2024 | 1000 | 0 | FLAT | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 4 | MONTHS | 1 | MONTHS | 4 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | SUBMITTED_ON_DATE |
Then LoanDetails has repaymentStartDateType field with value: "SUBMITTED_ON_DATE"
Then Loan Repayment schedule has 4 periods, with the following data for periods:
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
| | | 10 February 2024 | | 1000.0 | | | 0.0 | | 0.0 | | | | 0.0 |
Expand Down Expand Up @@ -356,6 +357,7 @@ Feature: LoanRepayment - Part4
When Admin creates a fully customized loan with the following data:
| LoanProduct | submitted on date | expected disbursement date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | Repayment start date type |
| LP2_DOWNPAYMENT_AUTO_ADVANCED_PAYMENT_ALLOCATION_REPAYMENT_START_SUBMITTED | 31 January 2024 | 10 February 2024 | 1000 | 0 | FLAT | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 4 | MONTHS | 1 | MONTHS | 4 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | DISBURSEMENT_DATE |
Then LoanDetails has repaymentStartDateType field with value: "DISBURSEMENT_DATE"
Then Loan Repayment schedule has 5 periods, with the following data for periods:
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
| | | 10 February 2024 | | 1000.0 | | | 0.0 | | 0.0 | | | | 0.0 |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ public class LoanAccountData {
private Boolean enableDownPayment;
private BigDecimal disbursedAmountPercentageForDownPayment;
private Boolean enableAutoRepaymentForDownPayment;
private EnumOptionData repaymentStartDateType;
private Boolean interestRecognitionOnDisbursementDate;

private EnumOptionData loanScheduleType;
Expand Down Expand Up @@ -444,6 +445,7 @@ public LoanAccountData withProductData(final LoanProductData product, final Inte
.setFixedPrincipalPercentagePerInstallment(product.getFixedPrincipalPercentagePerInstallment())
.setDelinquent(CollectionData.template()).setDisallowExpectedDisbursements(product.getDisallowExpectedDisbursements())
.setLoanScheduleType(product.getLoanScheduleType()).setLoanScheduleProcessingType(product.getLoanScheduleProcessingType())
.setRepaymentStartDateType(product.getRepaymentStartDateType())
.setInterestRecognitionOnDisbursementDate(product.isInterestRecognitionOnDisbursementDate())
.setDaysInYearCustomStrategyOptions(product.getDaysInYearCustomStrategyOptions())
.setDaysInYearCustomStrategy(product.getDaysInYearCustomStrategy());
Expand Down Expand Up @@ -482,14 +484,15 @@ public static LoanAccountData basicLoanDetails(final Long id, final String accou
final DelinquencyRangeData delinquencyRange, final boolean disallowExpectedDisbursements, final boolean fraud,
LocalDate lastClosedBusinessDate, LocalDate overpaidOnDate, final boolean chargedOff, final boolean enableDownPayment,
final BigDecimal disbursedAmountPercentageForDownPayment, final boolean enableAutoRepaymentForDownPayment,
final boolean enableInstallmentLevelDelinquency, final EnumOptionData loanScheduleType,
final EnumOptionData loanScheduleProcessingType, final Integer fixedLength, final StringEnumOptionData chargeOffBehaviour,
final boolean isInterestRecognitionOnDisbursementDate, final boolean allowFullTermForTranche,
final StringEnumOptionData daysInYearCustomStrategy, final boolean enableIncomeCapitalization,
final StringEnumOptionData capitalizedIncomeCalculationType, final StringEnumOptionData capitalizedIncomeStrategy,
StringEnumOptionData capitalizedIncomeType, final boolean enableBuyDownFee,
final StringEnumOptionData buyDownFeeCalculationType, final StringEnumOptionData buyDownFeeStrategy,
final StringEnumOptionData buyDownFeeIncomeType, final boolean merchantBuyDownFee) {
final EnumOptionData repaymentStartDateType, final boolean enableInstallmentLevelDelinquency,
final EnumOptionData loanScheduleType, final EnumOptionData loanScheduleProcessingType, final Integer fixedLength,
final StringEnumOptionData chargeOffBehaviour, final boolean isInterestRecognitionOnDisbursementDate,
final boolean allowFullTermForTranche, final StringEnumOptionData daysInYearCustomStrategy,
final boolean enableIncomeCapitalization, final StringEnumOptionData capitalizedIncomeCalculationType,
final StringEnumOptionData capitalizedIncomeStrategy, StringEnumOptionData capitalizedIncomeType,
final boolean enableBuyDownFee, final StringEnumOptionData buyDownFeeCalculationType,
final StringEnumOptionData buyDownFeeStrategy, final StringEnumOptionData buyDownFeeIncomeType,
final boolean merchantBuyDownFee) {

final CollectionData delinquent = CollectionData.template();

Expand Down Expand Up @@ -531,7 +534,7 @@ public static LoanAccountData basicLoanDetails(final Long id, final String accou
.setDelinquencyRange(delinquencyRange).setDisallowExpectedDisbursements(disallowExpectedDisbursements).setFraud(fraud)
.setLastClosedBusinessDate(lastClosedBusinessDate).setOverpaidOnDate(overpaidOnDate).setChargedOff(chargedOff)
.setEnableDownPayment(enableDownPayment).setDisbursedAmountPercentageForDownPayment(disbursedAmountPercentageForDownPayment)
.setEnableAutoRepaymentForDownPayment(enableAutoRepaymentForDownPayment)
.setEnableAutoRepaymentForDownPayment(enableAutoRepaymentForDownPayment).setRepaymentStartDateType(repaymentStartDateType)
.setEnableInstallmentLevelDelinquency(enableInstallmentLevelDelinquency).setLoanScheduleType(loanScheduleType)
.setLoanScheduleProcessingType(loanScheduleProcessingType).setFixedLength(fixedLength)
.setChargeOffBehaviour(chargeOffBehaviour).setInterestRecognitionOnDisbursementDate(isInterestRecognitionOnDisbursementDate)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@
import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
import org.apache.fineract.portfolio.loanproduct.domain.LoanSupportedInterestRefundTypes;
import org.apache.fineract.portfolio.loanproduct.domain.RepaymentStartDateType;
Comment thread
Aman-Mittal marked this conversation as resolved.
import org.apache.fineract.portfolio.rate.domain.Rate;
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDatedChecks;
import org.apache.fineract.useradministration.domain.AppUser;
Expand Down Expand Up @@ -432,9 +431,6 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
@Column(name = "allow_full_term_for_tranche", nullable = false)
private boolean allowFullTermForTranche = false;

@Column(name = "repayment_start_date_type_enum")
private RepaymentStartDateType repaymentStartDateType;

public static Loan newIndividualLoanApplication(final String accountNo, final Client client, final AccountType loanType,
final LoanProduct loanProduct, final Fund fund, final Staff officer, final CodeValue loanPurpose,
final LoanRepaymentScheduleTransactionProcessor transactionProcessingStrategy,
Expand Down Expand Up @@ -570,7 +566,7 @@ private Loan(final String accountNo, final Client client, final Group group, fin
this.expectedFirstRepaymentOnDate = loanApplicationTerms.getRepaymentStartFromDate();
this.interestChargedFromDate = loanApplicationTerms.getInterestChargedFromDate();
this.submittedOnDate = submittedOnDate != null ? submittedOnDate : DateUtils.getBusinessLocalDate();
this.repaymentStartDateType = loanApplicationTerms.getRepaymentStartDateType();
this.loanRepaymentScheduleDetail.setRepaymentStartDateType(loanApplicationTerms.getRepaymentStartDateType());

updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());

Expand Down Expand Up @@ -1848,8 +1844,4 @@ public boolean hasContractTerminationTransaction() {
public long getTermsCount() {
return getRepaymentScheduleInstallments().stream().filter(i -> !i.isDownPayment() && !i.isAdditional()).count();
}

public RepaymentStartDateType getRepaymentStartDateType() {
return this.repaymentStartDateType != null ? this.repaymentStartDateType : this.loanProduct.getRepaymentStartDateType();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1740,7 +1740,7 @@ public LoanProductRelatedDetail toLoanProductRelatedDetail() {
this.chargeOffBehaviour, this.interestRecognitionOnDisbursementDate, this.daysInYearCustomStrategy,
this.enableIncomeCapitalization, this.capitalizedIncomeCalculationType, this.capitalizedIncomeStrategy,
this.capitalizedIncomeType, this.installmentAmountInMultiplesOf, this.enableBuyDownFee, this.buyDownFeeCalculationType,
this.buyDownFeeStrategy, this.buyDownFeeIncomeType, this.merchantBuyDownFee);
this.buyDownFeeStrategy, this.buyDownFeeIncomeType, this.merchantBuyDownFee, this.repaymentStartDateType);
}

public ILoanConfigurationDetails toLoanConfigurationDetails() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public LoanApplicationTerms constructLoanApplicationTerms(final ScheduleGenerato
RecalculationFrequencyType compoundingFrequencyType = null;
LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
CalendarHistoryDataWrapper calendarHistoryDataWrapper;
RepaymentStartDateType repaymentStartDateType = loan.getRepaymentStartDateType();
RepaymentStartDateType repaymentStartDateType = loan.getLoanProductRelatedDetail().getRepaymentStartDateType();
boolean allowCompoundingOnEod = false;
if (loan.getLoanProductRelatedDetail().isInterestRecalculationEnabled()) {
restCalendarInstance = scheduleGeneratorDTO.getCalendarInstanceForInterestRecalculation();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,9 +228,6 @@ public class LoanProduct extends AbstractPersistableCustom<Long> {
@Column(name = "overdue_days_for_repayment_event")
private Integer overDueDaysForRepaymentEvent;

@Column(name = "repayment_start_date_type_enum", nullable = false)
private RepaymentStartDateType repaymentStartDateType;

public void updateLoanProductInRelatedClasses() {
if (this.isInterestRecalculationEnabled()) {
this.productInterestRecalculationDetails.updateProduct(this);
Expand Down Expand Up @@ -341,7 +338,7 @@ public LoanProduct(final Fund fund, final String transactionProcessingStrategyCo
supportedInterestRefundTypes, chargeOffBehaviour, isInterestRecognitionOnDisbursementDate, daysInYearCustomStrategy,
enableIncomeCapitalization, capitalizedIncomeCalculationType, capitalizedIncomeStrategy, capitalizedIncomeType,
installmentAmountInMultiplesOf, enableBuyDownFee, buyDownFeeCalculationType, buyDownFeeStrategy, buyDownFeeIncomeType,
merchantBuyDownFee);
merchantBuyDownFee, repaymentStartDateType);

this.loanProductMinMaxConstraints = new LoanProductMinMaxConstraints(defaultMinPrincipal, defaultMaxPrincipal,
defaultMinNominalInterestRatePerPeriod, defaultMaxNominalInterestRatePerPeriod, defaultMinNumberOfInstallments,
Expand Down Expand Up @@ -389,8 +386,6 @@ public LoanProduct(final Fund fund, final String transactionProcessingStrategyCo

this.dueDaysForRepaymentEvent = dueDaysForRepaymentEvent;
this.overDueDaysForRepaymentEvent = overDueDaysForRepaymentEvent;
this.repaymentStartDateType = repaymentStartDateType;

this.enableInstallmentLevelDelinquency = enableInstallmentLevelDelinquency;
validateLoanProductPreSave();
}
Expand Down Expand Up @@ -756,10 +751,6 @@ public boolean isEqualAmortization() {
return loanProductRelatedDetail.isEqualAmortization();
}

public RepaymentStartDateType getRepaymentStartDateType() {
return this.repaymentStartDateType == null ? RepaymentStartDateType.INVALID : this.repaymentStartDateType;
}

public void updateEnableInstallmentLevelDelinquency(boolean enableInstallmentLevelDelinquency) {
this.enableInstallmentLevelDelinquency = enableInstallmentLevelDelinquency;
}
Expand Down
Loading
Loading