Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FINERACT-2065: Schedule handling for fixed length configuration #3808

Conversation

alberto-art3ch
Copy link
Contributor

Description

Following with the Loan Product Fixed Length configuration we need to consider the schedule generation with this new setting.

We will get this with the next considerations:

  • Should be supported for zero interest bearing loan accounts only
  • Should be available for “advance payment allocation“
  • Validation should be in place when the fixed length cannot derive the no of repayments entered - system should not approve such config and we are creating a new BadFixedLengthException

FINERACT-2065.

Fixed_Length_Loan_Account.mov

Checklist

Please make sure these boxes are checked before submitting your pull request - thanks!

  • Write the commit message as per https://github.com/apache/fineract/#pull-requests

  • Acknowledge that we will not review PRs that are not passing the build ("green") - it is your responsibility to get a proposed PR to pass the build, not primarily the project's maintainers.

  • Create/update unit or integration tests for verifying the changes made.

  • Follow coding conventions at https://cwiki.apache.org/confluence/display/FINERACT/Coding+Conventions.

  • Add required Swagger annotation and update API documentation at fineract-provider/src/main/resources/static/legacy-docs/apiLive.htm with details of any API changes

  • Submission is not a "code dump". (Large changes can be made "in repository" via a branch. Ask on the developer mailing list for guidance, if required.)

FYI our guidelines for code reviews are at https://cwiki.apache.org/confluence/display/FINERACT/Code+Review+Guide.

Copy link
Contributor

@reluxa reluxa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add some unit / integration tests?

@alberto-art3ch alberto-art3ch force-pushed the enhancement/schedule_handling_for_fixed_length_configuration branch from f0f79ad to 15f0e4d Compare March 20, 2024 08:34
@@ -58,6 +61,7 @@ public LoanScheduleModel generate(final MathContext mc, final LoanApplicationTer
final ApplicationCurrency applicationCurrency = loanApplicationTerms.getApplicationCurrency();
// generate list of proposed schedule due dates
LocalDate loanEndDate = getScheduledDateGenerator().getLastRepaymentDate(loanApplicationTerms, holidayDetailDTO);
log.info("loanEndDate {}", loanEndDate);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this info logger...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, Removed!

@@ -102,6 +106,19 @@ public LoanScheduleModel generate(final MathContext mc, final LoanApplicationTer
// Loan Schedule Exceptions that need to be applied for Loan Account
LoanTermVariationParams termVariationParams = applyLoanTermVariations(loanApplicationTerms, scheduleParams, scheduledDueDate);
scheduledDueDate = termVariationParams.scheduledDueDate();
log.info("scheduledDueDate {}", scheduledDueDate);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this info logger...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, Removed!


isNextRepaymentAvailable = DateUtils.isBefore(scheduledDueDate, loanEndDate);
}
log.info("scheduledDueDate {}", scheduledDueDate);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this info logger...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, Removed!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed from this method and class


// Fixed Length Validations - If the Number or Repayments requested is greater than current/last
// Installment number
if (loanApplicationTerms.getFixedLength() != null
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be validated in the validator, not during the schedule generation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have talked about this, that validation will be keep it here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed from this method and class

log.info("scheduledDueDate {}", scheduledDueDate);

// Fixed Length Validations - Ensure the last repayment date equal to Fixed Length
if (loanApplicationTerms.getFixedLength() != null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont fully understand this here...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have talked about this in the session

}
lastRepaymentDate = adjustRepaymentDate(lastRepaymentDate, loanApplicationTerms, holidayDetailDTO).getChangedScheduleDate();
// Fixed Length validation - When the Number of Repayments is lower than Fixed Length
if (maxDateForFixedLength != null && DateUtils.isAfter(maxDateForFixedLength, lastRepaymentDate)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we do it twice?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have talked about this in the session

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (maxDateForFixedLength != null && DateUtils.isAfter(maxDateForFixedLength, lastRepaymentDate)) {
lastRepaymentDate = maxDateForFixedLength;
}
log.info("lastRepaymentDate {}", lastRepaymentDate);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove the info logger

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, Removed!


import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;

public class BadFixedLengthSetupException extends AbstractPlatformDomainRuleException {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We dont need a new exception. Please use the GenericPlatformDomainRuleException

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! removed

validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2023, 12, 22), 33.0, 0.0, 33.0, 0.0, 0.0);
validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2024, 1, 01), 34.0, 0.0, 34.0, 0.0, 0.0);
assertEquals(loanDetails.getNumberOfRepayments(), 3);
assertEquals(Utils.getDifferenceInDays(loanDetails.getTimeline().getActualDisbursementDate(), LocalDate.of(2024, 1, 01)),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should test the due date of the very last installment instead of hard coding a date...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, validations updated with the due date of the last period

validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2023, 12, 20), 33.0, 0.0, 33.0, 0.0, 0.0);
validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2023, 12, 27), 34.0, 0.0, 34.0, 0.0, 0.0);
assertEquals(loanDetails.getNumberOfRepayments(), 3);
assertEquals(Utils.getDifferenceInWeeks(loanDetails.getTimeline().getActualDisbursementDate(), LocalDate.of(2023, 12, 27)),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, validations updated with the due date of the last period

});
}

// UC127: Advanced payment allocation with Fixed Length for 11 months and Loan Term for 12 months (6 repayments
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a test case when the fixed lenght is longer than the loan term.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TC uc128 created

loanTransactionHelper.disburseLoan(loanResponse.getLoanId(),
new PostLoansLoanIdRequest().actualDisbursementDate("22 November 2023").dateFormat(DATETIME_PATTERN)
.transactionAmount(BigDecimal.valueOf(100.0)).locale("en"));

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add test cases where you are testing negative scenarios:

  • Providing invalid fixed length parameters

Copy link
Contributor

@adamsaghy adamsaghy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please kindly check my comments!

@alberto-art3ch alberto-art3ch force-pushed the enhancement/schedule_handling_for_fixed_length_configuration branch 2 times, most recently from b956079 to 4bd1621 Compare March 20, 2024 14:32
boolean isFirstRepayment = true;
for (int repaymentPeriod = 1; repaymentPeriod <= numberOfRepayments; repaymentPeriod++) {
lastRepaymentDate = generateNextRepaymentDate(lastRepaymentDate, loanApplicationTerms, isFirstRepayment);
isFirstRepayment = false;
// Fixed Length validation - When the Number of Repayments is greater than Fixed Length
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please correct these comments. This has nothing to do with the number of repayments... it checks whether the last repaymentDate is greater than the fixedLengthDate...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

break;
}
}
// Fixed Length validation - When the Number of Repayments is lower than Fixed Length
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please correct these comments. This has nothing to do with the number of repayments... it checks whether the last repaymentDate is lower than the fixedLengthDate...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

// Fixed Length validation - When the Number of Repayments is greater than Fixed Length
if (maxDateForFixedLength != null && DateUtils.isAfter(lastRepaymentDate, maxDateForFixedLength)) {
lastRepaymentDate = maxDateForFixedLength;
break;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind moving this condition out of the cycle, it does not require do to anything there. After the cycle finished you will have the lastRepaymentDate set, which is the due date of the last installment and after you can decide whether it needs to be changed or not:
if lastRepaymentDate is not equal with the fixedLengthDate, override it with the fixedLengthDate.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

@alberto-art3ch alberto-art3ch force-pushed the enhancement/schedule_handling_for_fixed_length_configuration branch from 4bd1621 to 88e5bd8 Compare March 22, 2024 06:27
lastRepaymentDate = generateNextRepaymentDate(lastRepaymentDate, loanApplicationTerms, isFirstRepayment);
isFirstRepayment = false;
LocalDate lastRepaymentDate = loanApplicationTerms.getRepaymentStartDate();
// When exists defined a Fixed Length value
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We dont really need this..

Please revert and just adjust the lastRepaymentDate after it got calculated (the after the for cycle) in the following manner:
if the lastRepaymentDate is not equals with calculatedMaxDateForFixedLenght than override the lastRepaymentDate with it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! updated

Copy link
Contributor

@adamsaghy adamsaghy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kindly check my review and please add the requested negative test scenarios!

@alberto-art3ch alberto-art3ch force-pushed the enhancement/schedule_handling_for_fixed_length_configuration branch from 88e5bd8 to c0b758f Compare March 25, 2024 06:25
@alberto-art3ch
Copy link
Contributor Author

Kindly check my review and please add the requested negative test scenarios!

The last change was already done and the negative case is the uc128

.numberOfRepayments(6).repaymentEvery(1).repaymentFrequencyType(repaymentFrequencyType.longValue()).fixedLength(6);
PostLoanProductsResponse loanProductResponse = loanProductHelper.createLoanProduct(product);

loanTransactionHelper.applyLoanWithError(new PostLoansRequest().clientId(client.getClientId())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should check whether the provided exception and message is correct or not.

Copy link
Contributor

@adamsaghy adamsaghy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see my comments and kindly fix the conflicts!

@alberto-art3ch alberto-art3ch force-pushed the enhancement/schedule_handling_for_fixed_length_configuration branch 2 times, most recently from ec1cf2a to c2894da Compare March 25, 2024 19:36
@adamsaghy
Copy link
Contributor

@alberto-art3ch Please fix the code format error!

@alberto-art3ch alberto-art3ch force-pushed the enhancement/schedule_handling_for_fixed_length_configuration branch from c2894da to b416bfc Compare March 26, 2024 09:12
Copy link
Contributor

@adamsaghy adamsaghy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@alberto-art3ch alberto-art3ch force-pushed the enhancement/schedule_handling_for_fixed_length_configuration branch from b416bfc to a38273b Compare March 26, 2024 14:31
interestRatePerPeriod);
}

if (fixedLength != null && numberOfRepayments.compareTo(fixedLength) > 0) {
Copy link
Contributor

@adamsaghy adamsaghy Mar 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is incorrect...
Example which should work:

  • number of repayments: 3
  • Repay every: 15 DAYS
  • Loan term: 45 DAYS
  • Fixed term length: 40 days

Copy link
Contributor

@adamsaghy adamsaghy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alberto-art3ch alberto-art3ch force-pushed the enhancement/schedule_handling_for_fixed_length_configuration branch from a38273b to 23627a4 Compare March 26, 2024 20:33
@alberto-art3ch alberto-art3ch force-pushed the enhancement/schedule_handling_for_fixed_length_configuration branch from 23627a4 to 160c5a2 Compare March 27, 2024 03:28
Copy link
Contributor

@adamsaghy adamsaghy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@adamsaghy adamsaghy merged commit b64b4b7 into apache:develop Mar 27, 2024
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants