Adam Saghy created FINERACT-2936:
------------------------------------

             Summary: Fix daysInYearCustomStrategy plumbing defects in the loan 
and loan product APIs
                 Key: FINERACT-2936
                 URL: https://issues.apache.org/jira/browse/FINERACT-2936
             Project: Apache Fineract
          Issue Type: Bug
          Components: Loan
    Affects Versions: 1.15.0
            Reporter: Adam Saghy
            Assignee: Adam Saghy


*Requires a regenerated Fineract client (swagger / OpenAPI changes)*
 * LoansApiResourceSwagger.PostLoansRequest (line 1408): allowableValues is one 
string, "FULL_LEAP_YEAR, FEB_29_PERIOD_ONLY". The generated client enum 
therefore has a single merged constant, FULL_LEAP_YEAR_FEB_29_PERIOD_ONLY, and 
can't send a real value. Change it to an array: {"FULL_LEAP_YEAR", 
"FEB_29_PERIOD_ONLY"}.

 ** *Decision: Add it*

 * LoansApiResourceSwagger.GetLoansLoanIdResponse (line 105) has no 
daysInYearCustomStrategy, and 
LoanProductsApiResourceSwagger.GetLoanProductsTemplateResponse (line 755) has 
no daysInYearCustomStrategyOptions. The server already returns both; only the 
generated models lack them. This is additive.

 ** *Decision: Add it*

*Server-only (behaviour changes)*
 * LoanApplicationValidator.validateForCreate (line 777): passes the string 
literal "daysInYearCustomStrategyParameterName" to enumValueOfParameterNamed 
instead of the constant LoanApiConstants.daysInYearCustomStrategyParameterName. 
The lookup always returns null, so the progressive-only and ACTUAL-only checks 
(lines 775–791) never run.

 ** *Decision: Fix it*

 * LoanScheduleAssembler.assembleLoanApplicationTermsFrom (line 576): always 
passes the product's value to LoanApplicationTerms.assembleFrom. The loan 
request's value is never read, even though LoanApplicationValidator accepts the 
parameter (supported parameters, line 178). It is silently ignored.

 ** *Decision:* Fix by implementing a per-loan override (like 
interestRecognitionOnDisbursementDate)

 * LoanApplicationTerms(Builder builder) (private constructor, line 308): never 
copies builder.daysInYearCustomStrategy into the new object. 
assembleFrom(LoanRepaymentScheduleModelData, MathContext) does set it on the 
Builder (line 615), but the value is dropped when build() runs. As a result the 
embeddable progressive schedule generator ignores the strategy.

 ** *Decision: Fix it, but i wonder why it was not an issue during testing*

 * LoanProductRelatedDetailUpdateUtil.updateLoanRepaymentSchedule (lines 
277–280): uses 
DaysInYearCustomStrategyType.valueOf(command.stringValueOfParameterNamed(...)).

 ** An explicit "daysInYearCustomStrategy": null becomes valueOf(""), which 
throws an IllegalArgumentException, most likely a 500. So the value can't be 
cleared via PUT.

 ** Clearing is needed: LoanProduct.validateLoanProductPreSave (lines 464–474) 
requires it to be null for cumulative products and for non-ACTUAL days in year. 
A product that has it set can't be switched to either.

 ** There's no changed-value check either, so every PUT that sends it reports 
it as changed.

 ** *Decision: Fix it, we should be able to clear it if it’s cumulative or 
“non-Actual” days in year, otherwise it needs to have a value*

 * LoanProductDataValidator.validateForCreate / validateForUpdate (lines 233 / 
1345): daysInYearCustomStrategyis the only string-enum product parameter 
without an isOneOfEnumValues check; it's only listed as supported (line 203). 
An invalid value on create is rejected late, by LoanProductAssembler's generic 
enum parsing (line 212). On update it reaches 
DaysInYearCustomStrategyType.valueOf(...) in 
LoanProductRelatedDetailUpdateUtil(line 279), which most likely fails with a 
500.

 ** *Decision: Fix it*

 * 
AdvancedPaymentScheduleTransactionProcessor.handleReAgeWithInterestRecalculationEnabled
 (lines 4283–4291): builds the re-age LoanApplicationTerms with 
daysInMonthType, daysInYearType, interestRecognitionOnDisbursementDate, 
daysInYearCustomStrategy and allowPartialPeriodInterestCalculationread from the 
*product* (loan.getLoanProduct()…), not from the loan's own copy. The rest of 
the builder already reads from the loan.

 ** Changing any of these on the product leaks into existing loans when they're 
re-aged.

 ** interestRecognitionOnDisbursementDate can be overridden per loan at 
submission, so re-age ignores that override even when the product is never 
changed.

 ** (Possibly related: installmentAmountInMultiplesOf is read from the product 
at line 1788, in the capitalized-income handling.)

 * 
 ** *Decision: Fix it*



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to