adamsaghy commented on PR #6477:
URL: https://github.com/apache/fineract/pull/6477#issuecomment-5777818898

   @mariiaKraievska Please review my concerns / findings:
   
   
   1. updateFrom resolves the bucket before the change check
   
   WorkingCapitalLoanAssemblerImpl.java:420-429
   
   if (fromApiJsonHelper.parameterExists(delinquencyBucketIdParamName, 
element)) {
       final Long bucketId = ...;
       final DelinquencyBucket bucket = 
resolver.findWorkingCapitalBucketByIdIfProvided(bucketId); // always runs
       final Long existingBucketId = ...;
       if (!Objects.equals(bucketId, existingBucketId)) { ... }
   }
   
   The lookup + type validation runs unconditionally, outside the 
!Objects.equals(...) guard. The three sibling blocks around it (breachId, 
nearBreachId, delinquencyGraceDays) all gate the lookup on the change check. 
Consequence: a WC loan created before this PR with a REGULAR bucket (the old 
code was findById(bucketId).orElse(null) with no type check, so this was 
reachable) can no longer be modified at all if the client resends the unchanged 
delinquencyBucketId — it 400s on a no-op. Same shape for a since-deleted id, 
which used to be silently ignored and now throws 
DelinquencyBucketNotFoundException.
   
   Moving the resolve inside the if fixes both and matches the surrounding 
style. The WC product update path already does this correctly via 
isChangeInLongParameterNamed 
(WorkingCapitalLoanProductWritePlatformServiceImpl.java:276), as does the LP 
update path.
   
   2. Error codes and unused message args
   
   Both new errors pass the bucket id as a defaultUserMessageArgs value, but 
neither message has a {0} placeholder, so it's never rendered. The codes also 
drop the entity segment that the rest of the codebase uses 
(validation.msg.delinquencyBucketId.must.be.regular.type vs. the conventional 
validation.msg.loanproduct.delinquencyBucketId.…). The two messages are 
otherwise near-identical — one code parameterized by expected type would do.
   
   3. retrieveWorkingCapitalDelinquencyBucketOptions() returns null when empty
   
   WorkingCapitalDelinquencyBucketResolver.java:46-50. This preserves the old 
serialization behaviour, but it pushes null-returning into a shared service 
method that now has two callers (WC product template and, transitively, the WC 
loan template). Returning List.of() and keeping the null-ing at the 
response-building boundary would be safer.
   
   4. Duplication
   
   retrieveAllDelinquencyBuckets() and retrieveDelinquencyBucketsByType() are 
identical apart from the finder 
(DelinquencyReadPlatformServiceImpl.java:105-119). Also 
validateIsWorkingCapitalType is public but only called from within its own 
class.
   
   5. Test-side nits
   
   DelinquencyBucketResolver.resolveBucketId calls resolve(...) on this, so 
Spring's @Cacheable proxy is bypassed — every resolution re-fetches all 
buckets. Not a correctness issue.
   WorkingCapitalLoanAccount.feature still hardcodes delinquencyBucketId | 1 in 
three existing scenarios. Harmless today (buildCreateLoanRequest ignores column 
7, and the negative scenario fails in the validator before the assembler), but 
the seeded bucket ids are genuinely nondeterministic — 
DelinquencyGlobalInitializerStep.initialize() creates BASIC_DELINQUENCY_BUCKET 
and WC_DELINQUENCY_BUCKET via ParallelExecutionHelper.runInParallel. Now that 
resolveBucketId accepts names, those literals are worth converting before 
someone wires column 7 up.
   LoanProduct.feature C106741 creates a loan product and leaves it behind; the 
WC counterpart C106744 deletes its product.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to