Copilot commented on code in PR #6106:
URL: https://github.com/apache/fineract/pull/6106#discussion_r3546919607


##########
fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingHelper.java:
##########
@@ -613,7 +610,6 @@ private void savePaymentChannelToFundSourceMapping(final 
Long productId, final L
      */
     private void saveChargeToFundSourceMapping(final Long productId, final 
Long chargeId, final Long incomeAccountId,
             final PortfolioProductType portfolioProductType, final boolean 
isPenalty) {
-        final Charge charge = 
this.chargeRepositoryWrapper.findOneWithNotFoundDetection(chargeId);
 
         // TODO Vishwas: Need to validate if given charge is fee or Penalty
         // based on input condition

Review Comment:
   `saveChargeToFundSourceMapping` no longer verifies that the provided 
`chargeId` exists (previously this was implicitly validated by loading the 
`Charge` entity). Because `acc_product_mapping.charge_id` has no FK constraint 
to `m_charge`, this can persist orphaned mappings that will never be returned 
by the join-based read queries, and may lead to confusing downstream behavior. 
Consider validating `chargeId` (and optionally `m_charge.is_penalty` vs 
`isPenalty`) via a lightweight JDBC lookup, or by delegating to an existing 
charge read contract that does not reintroduce a domain dependency.



##########
fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java:
##########
@@ -257,16 +262,27 @@ public List<ChargeToGLAccountMapper> 
fetchPenaltyToIncomeAccountMappingsForSavin
 
     private List<ChargeToGLAccountMapper> 
fetchChargeToIncomeAccountMappings(final PortfolioProductType 
portfolioProductType,
             final Long loanProductId, final boolean penalty) {
-        final List<ProductToGLAccountMapping> mappings = penalty
-                ? 
productToGLAccountMappingRepository.findAllPenaltyMappings(loanProductId, 
portfolioProductType.getValue())
-                : 
productToGLAccountMappingRepository.findAllFeeMappings(loanProductId, 
portfolioProductType.getValue());
-
-        List<ChargeToGLAccountMapper> chargeToGLAccountMappers = 
mappings.isEmpty() ? null : new ArrayList<>();
-        for (final ProductToGLAccountMapping mapping : mappings) {
-            final GLAccountData gLAccountData = new 
GLAccountData().setId(mapping.getGlAccount().getId())
-                    
.setName(mapping.getGlAccount().getName()).setGlCode(mapping.getGlAccount().getGlCode());
-            final ChargeData chargeData = 
ChargeData.builder().id(mapping.getCharge().getId()).name(mapping.getCharge().getName())
-                    .penalty(mapping.getCharge().isPenalty()).build();
+        // The accounting module is decoupled from the charge domain, so we 
cannot navigate a Charge association in
+        // JPQL. We read the charge -> income-account rows via JdbcTemplate 
instead of a JPA native query: EclipseLink
+        // does not bind Spring Data ":name" parameters in native queries (it 
expects "#name"), which caused the raw
+        // markers to reach the database. JdbcTemplate uses plain JDBC 
positional binding and works on all supported
+        // databases. Column order: [0] gl_account_id, [1] charge id, [2] 
charge name. The penalty flag is known from
+        // the method argument, so it is inlined as a boolean literal (never 
user input) rather than bound.

Review Comment:
   This JDBC implementation does an extra JPA lookup per row 
(`glAccountRepository.findById` inside the loop), creating an N+1 query pattern 
and additional transaction overhead. Since all required GL account fields come 
from `acc_gl_account`, consider selecting the GL account name/code directly in 
the SQL and mapping straight to `GLAccountData`; this also lets you bind the 
`penalty` flag as a parameter instead of concatenating it into the SQL string.



##########
fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java:
##########
@@ -312,6 +328,7 @@ private List<ClassificationToGLAccountData> 
fetchClassificationMappings(final Po
                         : 
productToGLAccountMappingRepository.findAllBuyDownFeeClassificationsMappings(loanProductId,
                                 portfolioProductType.getValue());
 
+        
productToGLAccountMappingRepository.findAllChargeOffReasonsMappings(loanProductId,
 portfolioProductType.getValue());

Review Comment:
   This call to `findAllChargeOffReasonsMappings(...)` is unused and triggers 
an extra database query on every classification mapping fetch. It looks like a 
leftover line and should be removed to avoid unnecessary load and confusion.



##########
fineract-accounting/dependencies.gradle:
##########
@@ -25,6 +25,7 @@ dependencies {
     // implementation dependencies are directly used (compiled against) in 
src/main (and src/test)
     //
     implementation(project(path: ':fineract-core'))
+    testImplementation 'org.springframework.modulith:spring-modulith-core'
     implementation(project(path: ':fineract-charge'))

Review Comment:
   After the code changes in this PR, `fineract-accounting` no longer imports 
any types from the `fineract-charge` module (only `ChargeData`, which is in 
`fineract-core`). Keeping `implementation(project(path: ':fineract-charge'))` 
preserves a build-time coupling that appears contrary to the PR’s stated goal 
of decoupling accounting from charge. If nothing else in this module depends on 
`:fineract-charge`, consider removing this dependency.



##########
fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/WorkingCapitalLoanProductAdvancedAccountingReadHelper.java:
##########
@@ -74,17 +79,26 @@ public List<AdvancedMappingToExpenseAccountData> 
fetchWriteOffReasonMappings(fin
     }
 
     private List<ChargeToGLAccountMapper> fetchChargeToIncomeMappings(final 
Long wcLoanProductId, final boolean penalty) {
-        final List<ProductToGLAccountMapping> mappings = penalty
-                ? 
productToGLAccountMappingRepository.findAllPenaltyMappings(wcLoanProductId,
-                        PortfolioProductType.WORKING_CAPITAL_LOAN.getValue())
-                : 
productToGLAccountMappingRepository.findAllFeeMappings(wcLoanProductId,
-                        PortfolioProductType.WORKING_CAPITAL_LOAN.getValue());
+        // The charge name lives on m_charge, not on ProductToGLAccountMapping 
(which only stores charge_id), and the
+        // accounting module is decoupled from the charge domain, so we read 
the charge -> income-account rows via
+        // JdbcTemplate rather than a JPA native query (EclipseLink does not 
bind Spring Data ":name" markers in native
+        // queries). Column order: [0] gl_account_id, [1] charge id, [2] 
charge name. The penalty flag is known from the
+        // method argument, so it is inlined as a boolean literal (never user 
input) rather than bound.

Review Comment:
   Same as in `ProductToGLAccountMappingReadPlatformServiceImpl`: this method 
performs an extra JPA lookup per mapping row (`glAccountRepository.findById`), 
which can become an N+1 pattern. Prefer selecting the needed GL account fields 
directly in the SQL (joining `acc_gl_account`) and mapping straight to 
`GLAccountData`; also bind the `penalty` flag as a JDBC parameter instead of 
concatenating it.



##########
fineract-accounting/build.gradle:
##########
@@ -48,6 +48,11 @@ configurations {
 
 apply from: 'dependencies.gradle'
 
+test {
+    maxHeapSize = '2g'
+    jvmArgs += ['-XX:MaxMetaspaceSize=1g']
+}

Review Comment:
   This increases the JVM limits for *all* accounting tests (`maxHeapSize = 
'2g'` and `MaxMetaspaceSize=1g`). If this was added solely to support the new 
Modulith/ArchUnit boundary test, consider scoping the higher memory settings to 
just that test (e.g., a dedicated Gradle `Test` task or a property-controlled 
switch) to avoid inflating resource usage across the entire test suite and on 
developer machines.



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