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-2102: Loan Product enableDownPayment overrided in the Loan a… #3952

Conversation

alberto-art3ch
Copy link
Contributor

…pplication

Description

There is need to decide dynamically the loan is downpayment loan or not under the same product constraints. The change here to allow override previously configured enableDownPayment field

FINERACT-2102

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.

@@ -835,6 +835,12 @@ public Map<String, Object> updateFrom(JsonCommand command, Loan loan) {
loan.updateLoanRates(rateAssembler.fromParsedJson(command.parsedJson()));
}

if (command.hasParameter(LoanProductConstants.ENABLE_DOWN_PAYMENT)) {
Copy link
Contributor

@adamsaghy adamsaghy Jun 27, 2024

Choose a reason for hiding this comment

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

Please follow the same logic as it was done when loan was submitted:

  • You can disable down payment on loan, when the it was allowed on the loan product, but not the otherwise! It should fail with validation when not allowed action was tried:
  • user tries to enable down payment but it was not configured on loan product!
    Ignoring the field silently that was sent is wrong!

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! new validation method implemented in the LoanScheduleValidator

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 review!

@alberto-art3ch alberto-art3ch force-pushed the enhancement/downpayment_override_loan_account branch from 65d1860 to f87752c Compare July 3, 2024 02:40
@@ -466,7 +467,9 @@ private LoanApplicationTerms assembleLoanApplicationTermsFrom(final JsonElement
final boolean isPrincipalCompoundingDisabledForOverdueLoans = this.configurationDomainService
.isPrincipalCompoundingDisabledForOverdueLoans();

final boolean isDownPaymentEnabled = loanProduct.getLoanProductRelatedDetail().isEnableDownPayment();
final boolean isDownPaymentEnabled = validateDownPaymentAttribute(loanProduct.getLoanProductRelatedDetail().isEnableDownPayment(),
Copy link
Contributor

Choose a reason for hiding this comment

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

Please move this into the loan validator!

@@ -1379,6 +1382,21 @@ public void updateLoanApplicationAttributes(JsonCommand command, Loan loan, Map<
changes.put(LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM, newValue);
loanProductRelatedDetail.setEqualAmortization(newValue);
}

final boolean isDownPaymentEnabled = validateDownPaymentAttribute(
Copy link
Contributor

Choose a reason for hiding this comment

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

Please move this into the loan validator!

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!

loan.loanProduct().getLoanProductRelatedDetail().isEnableDownPayment(), command.parsedJson());
if (isDownPaymentEnabled != loanProductRelatedDetail.isEnableDownPayment()) {
changes.put(LoanProductConstants.ENABLE_DOWN_PAYMENT, isDownPaymentEnabled);
loanProductRelatedDetail.setEnableDownPayment(isDownPaymentEnabled);
Copy link
Contributor

Choose a reason for hiding this comment

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

Its more straightforward to set the values as "false" instead of assigning the value of the isDownPaymentEnabled which cannot be anything else but false.

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 need to consider a couple of scenarios:

  1. LP with DownPayment enabled and originally the LA with DownPayment enabled, then LA disable DownPayment, and
    2.LP with DownPayment enabled and originally the LA with DownPayment disabled, then LA enable DownPayment

This is why we are validating If we have a change in the new value compared with the old value

Copy link
Contributor

Choose a reason for hiding this comment

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

You are checking the loan product configuration, but what you should check is only the configuration on loan. This method is covering the update loan application part, we already have something configured on the loan, thats the only thing that should be checked!

If on the loan product it was enabled down payment, but it was disabled when the loan was submitted and now when the loan is got updated, we want to enable again, you should not check what was set on the loan product, but check whether on the loan level what was set and now during the update if we wanna change it and enable again, then we can set from the loan product the down payment configurations on the loan level again.

private boolean validateDownPaymentAttribute(final boolean isDownPaymentEnabledInLoanProduct, final JsonElement element) {
boolean isDownPaymentEnabled = isDownPaymentEnabledInLoanProduct;
if (!isDownPaymentEnabledInLoanProduct) {
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.ENABLE_DOWN_PAYMENT, element)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This is wrong. We should only throw exception if the the down payment is disabled on the loan product (which is correctly checked) and when user tries to set down payment to be enabled during loan submission (this is the wrongly checked part)! If user provide enableDownPayment=false then nothing should happen: No violation!

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! Logic updated

@@ -1446,4 +1464,21 @@ public Pair<Loan, Map<String, Object>> assembleLoanApproval(AppUser currentUser,

return Pair.of(loan, actualChanges);
}

private boolean validateDownPaymentAttribute(final boolean isDownPaymentEnabledInLoanProduct, final JsonElement element) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Please move the validations into the Validator class!

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! moved to the validator

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 see my review!

@alberto-art3ch alberto-art3ch force-pushed the enhancement/downpayment_override_loan_account branch from f87752c to 5f5585e Compare July 4, 2024 04:31
@@ -91,9 +91,14 @@ public class LoanSummaryData {
private BigDecimal totalCreditBalanceRefundReversed;
private BigDecimal totalRepaymentTransaction;
private BigDecimal totalRepaymentTransactionReversed;
private BigDecimal totalInterestRefund;
Copy link
Contributor

Choose a reason for hiding this comment

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

totalInterestRefund is not yet calculated. Please remove till it got implemented fully.

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

private final Long chargeOffReasonId;
private final String chargeOffReason;

private BigDecimal totalUnpaidAccruedDueInterest;
Copy link
Contributor

Choose a reason for hiding this comment

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

totalUnpaidAccruedDueInterest and totalUnpaidAccruedNotDueInterest are not set with value. Please compute their value or remove them till it got implemented fully.

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

@@ -58,7 +58,7 @@ private LocalDate getEffectiveDate() {
}

private boolean isBackdatedCharge() {
return loanCharge.get().getDueDate().isBefore(loanCharge.get().getSubmittedOnDate());
return (loanCharge.get().getDueDate() != null && loanCharge.get().getDueDate().isBefore(loanCharge.get().getSubmittedOnDate()));
Copy link
Contributor

Choose a reason for hiding this comment

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

This change is unrelated. If this is a fix for something, please raise it in a new PR!

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, It belongs to an issue when you have a Loan Installment Fee

@@ -63,8 +63,7 @@ public enum LoanTransactionType {
DOWN_PAYMENT(28, "loanTransactionType.downPayment"), //
REAGE(29, "loanTransactionType.reAge"), //
REAMORTIZE(30, "loanTransactionType.reAmortize"), //
INTEREST_PAYMENT_WAIVER(31, "loanTransactionType.interestPaymentWaiver"), //
;
INTEREST_PAYMENT_WAIVER(31, "loanTransactionType.interestPaymentWaiver"); //
Copy link
Contributor

Choose a reason for hiding this comment

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

This is unrelated change. Please remove 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! Removed

@@ -636,6 +636,10 @@ private GetLoansLoanIdFeeFrequency() {}
@Schema(example = "0.000000")
public Double totalRepaymentTransaction;
@Schema(example = "0.000000")
public Double totalInterestRefund;
Copy link
Contributor

Choose a reason for hiding this comment

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

totalInterestRefund is not set properly. Please remove till!

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

@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.

Seems like you mixed together different PRs! Please remove the unrelated changes!

@@ -64,13 +64,22 @@ public CollectionData getOverdueCollectionData(final Loan loan, List<LoanDelinqu
return CollectionData.template();
}

BigDecimal delinquentPrincipal = BigDecimal.ZERO;
Copy link
Contributor

Choose a reason for hiding this comment

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

unrelated changes!

@@ -466,7 +468,9 @@ private LoanApplicationTerms assembleLoanApplicationTermsFrom(final JsonElement
final boolean isPrincipalCompoundingDisabledForOverdueLoans = this.configurationDomainService
.isPrincipalCompoundingDisabledForOverdueLoans();

final boolean isDownPaymentEnabled = loanProduct.getLoanProductRelatedDetail().isEnableDownPayment();
final boolean isDownPaymentEnabled = loanScheduleValidator
Copy link
Contributor

Choose a reason for hiding this comment

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

Validations are called when loan got submitted or updated:
LoanApplicationWritePlatformServiceJpaRepositoryImpl.submitApplication
and
LoanApplicationWritePlatformServiceJpaRepositoryImpl.modifyApplication

Please move the validations into the loanApplicationValidator.validateForCreate and loanApplicationValidator.validateForModify

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! All the validations are in the LoanScheduleValidator class

@@ -176,4 +178,24 @@ private void validateRepaymentsStartingFromDateIsAfterDisbursementDate(final Lis
dataValidationErrors.add(error);
}
}

public boolean validateDownPaymentAttribute(final boolean isDownPaymentEnabledInLoanProduct, final JsonElement element) {
boolean isDownPaymentEnabled = isDownPaymentEnabledInLoanProduct;
Copy link
Contributor

@adamsaghy adamsaghy Jul 4, 2024

Choose a reason for hiding this comment

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

This method is overcomplicated:

public void validateDownPaymentAttribute(final boolean isDownPaymentEnabledInLoanProduct, final JsonElement element) {
      Boolean inputIsDownPaymentEnabled = this.fromApiJsonHelper.extractBooleanNamed(LoanProductConstants.ENABLE_DOWN_PAYMENT, element);
      if(!isDownPaymentEnabledInLoanProduct && Boolean.TRUE.equals(inputIsDownPaymentEnabled)) {
               throw new GeneralPlatformDomainRuleException("error.msg.downpayment.is.not.enabled.in.loan.product",
                        "The Loan can not override the downpayment flag because in the Loan Product the downpayment is disabled",
                        inputIsDownPaymentEnabled);
                        }
}

What do you think?

P.S.: You can consider passing the whole loan product as parameter and the validation method will decide what it is using from. Similarly the whole command passed as 2nd parameter

@@ -1379,6 +1383,22 @@ public void updateLoanApplicationAttributes(JsonCommand command, Loan loan, Map<
changes.put(LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM, newValue);
loanProductRelatedDetail.setEqualAmortization(newValue);
}

final boolean isDownPaymentEnabled = loanScheduleValidator
Copy link
Contributor

Choose a reason for hiding this comment

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

We only need the incoming isDownPaymentEnabled and if it is different than the one on the loan actually set then either set the LP config or reset it (based on we enable or disable 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! In the LoanScheduleAssembler is only the input read If exists, else we set the LP value

@alberto-art3ch alberto-art3ch force-pushed the enhancement/downpayment_override_loan_account branch from 5f5585e to 28ff499 Compare July 4, 2024 18:03
@@ -110,6 +110,7 @@ public CollectionData getOverdueCollectionData(final Loan loan, List<LoanDelinqu
collectionData.setDelinquentDate(overdueSinceDate);
}
collectionData.setDelinquentAmount(outstandingAmount);

Copy link
Contributor

Choose a reason for hiding this comment

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

Unrelated changes, please remove!

@@ -110,6 +111,8 @@ public static LoanSummaryData withTransactionAmountsSummary(final LoanSummaryDat
BigDecimal totalCreditBalanceRefundReversed = BigDecimal.ZERO;
BigDecimal totalRepaymentTransaction = BigDecimal.ZERO;
BigDecimal totalRepaymentTransactionReversed = BigDecimal.ZERO;
BigDecimal totalInterestRefund = BigDecimal.ZERO;
Copy link
Contributor

Choose a reason for hiding this comment

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

Unrelated changes, please remove!

@@ -131,6 +134,8 @@ public static LoanSummaryData withTransactionAmountsSummary(final LoanSummaryDat
loanTransactions);
totalRepaymentTransaction = computeTotalRepaymentTransactionAmount(loanTransactions);
totalRepaymentTransactionReversed = computeTotalAmountForReversedTransactions(LoanTransactionType.REPAYMENT, loanTransactions);
totalInterestPaymentWaiver = computeTotalAmountForNonReversedTransactions(LoanTransactionType.INTEREST_PAYMENT_WAIVER,
Copy link
Contributor

Choose a reason for hiding this comment

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

Unrelated changes, please remove!

@@ -163,7 +168,7 @@ public static LoanSummaryData withTransactionAmountsSummary(final LoanSummaryDat
.totalChargeAdjustment(totalChargeAdjustment).totalChargeAdjustmentReversed(totalChargeAdjustmentReversed)
.totalChargeback(totalChargeback).totalCreditBalanceRefund(totalCreditBalanceRefund)
.totalCreditBalanceRefundReversed(totalCreditBalanceRefundReversed).totalRepaymentTransaction(totalRepaymentTransaction)
.totalRepaymentTransactionReversed(totalRepaymentTransactionReversed).build();
Copy link
Contributor

Choose a reason for hiding this comment

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

Unrelated changes, please remove!

@@ -58,7 +58,7 @@ private LocalDate getEffectiveDate() {
}

private boolean isBackdatedCharge() {
return loanCharge.get().getDueDate().isBefore(loanCharge.get().getSubmittedOnDate());
return (loanCharge.get().getDueDate().isBefore(loanCharge.get().getSubmittedOnDate()));
Copy link
Contributor

Choose a reason for hiding this comment

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

Unrelated changes, please remove!

@@ -1004,6 +1004,14 @@ private GetLoansLoanIdDelinquencySummary() {}
public LocalDate delinquentDate;
@Schema(example = "100.000000")
public Double delinquentAmount;
@Schema(example = "80.000000")
Copy link
Contributor

Choose a reason for hiding this comment

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

Unrelated changes, please remove!

if (isDownPaymentEnabled != loanProductRelatedDetail.isEnableDownPayment()) {
changes.put(LoanProductConstants.ENABLE_DOWN_PAYMENT, isDownPaymentEnabled);
loanProductRelatedDetail.setEnableDownPayment(isDownPaymentEnabled);
loanProductRelatedDetail.setEnableAutoRepaymentForDownPayment(isDownPaymentEnabled);
Copy link
Contributor

Choose a reason for hiding this comment

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

Just because down payment was enabled, it does not mean auto repayment for down payment should be enabled as well. It should be set based on what was configured on the loan product

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! We are just changing the enableDownPayment attribute

@alberto-art3ch alberto-art3ch force-pushed the enhancement/downpayment_override_loan_account branch from 28ff499 to 86964b7 Compare July 4, 2024 20:39
@alberto-art3ch alberto-art3ch force-pushed the enhancement/downpayment_override_loan_account branch from 86964b7 to 1077fdd Compare July 5, 2024 15:44
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 5093ca7 into apache:develop Jul 8, 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
Development

Successfully merging this pull request may close these issues.

2 participants