Farooq Ayoade created FINERACT-2712:
---------------------------------------

             Summary: Bulk-import loan and savings account-opening download 
templates throw HTTP 500 (IllegalArgumentException: The workbook already 
contains this name) when two products or two charges share a name
                 Key: FINERACT-2712
                 URL: https://issues.apache.org/jira/browse/FINERACT-2712
             Project: Apache Fineract
          Issue Type: Bug
          Components: DataImportTool
            Reporter: Farooq Ayoade


---Observed behavior

  GET /v1/loans/downloadtemplate and GET /v1/savingsaccounts/downloadtemplate 
return HTTP 500 on a tenant that has two
  products (or, for loans, two charges) sharing a name:

  {noformat}
  java.lang.IllegalArgumentException: The workbook already contains this name: 
CHARGE_NAME_Processing_fee
      at org.apache.poi.hssf.usermodel.HSSFName.setNameName(...)
      at 
...populator.loan.LoanWorkbookPopulator.setNames(LoanWorkbookPopulator.java)

  java.lang.IllegalArgumentException: The workbook already contains this name: 
Interest_Rate_TARGET_SAVINGS
      at 
...populator.savings.SavingsWorkbookPopulator.setNames(SavingsWorkbookPopulator.java)
  {noformat}

  Expected behavior

  The template downloads successfully (HTTP 200). Each distinct product/charge 
name contributes its per-product/per-charge
  defined names once; a repeated name does not add a second, colliding defined 
name.
  
  Steps to reproduce

  1. Create two loan (or savings) products with the same name, e.g. two 
products named "TARGET SAVINGS"; or two loan
  charges named "Processing fee".
  2. GET 
/fineract-provider/api/v1/savingsaccounts/downloadtemplate?dateFormat=dd%20MMMM%20yyyy
 (or /loans/...).
  3. Observe HTTP 500 with The workbook already contains this name: 
<PREFIX>_<name>.

  Root cause
  
  LoanWorkbookPopulator.setNames() and SavingsWorkbookPopulator.setNames() 
build per-product (and, for loans,
  per-charge) Excel defined names keyed by the product/charge name, without 
de-duplication:

  {code:java}
  for (int i = 0; i < products.size(); i++) {
      ...
      String productName = products.get(i).getName()...;
      setSanitized(interestRateName, "Interest_Rate_" + productName);   // 
second product with same name -> collision
      ...
  }
  {code}
  
  When two products (or charges) resolve to the same defined name, 
createName().setNameName(...) is called twice with the
  same name and POI throws IllegalArgumentException: The workbook already 
contains this name, 500-ing the template. Note
  that Excel defined names are case-insensitive, so two products whose names 
differ only in case and/or surrounding
  whitespace (e.g. Target Savings and TARGET SAVINGS ) also collide. The 
loan-repayment / transaction templates already
  got an analogous guard for the per-client account names; the product/charge 
loops in the opening templates were missed.

  Proposed fix

  Track the product/charge names already emitted in a Set<String> and skip a 
repeated name, so each name's defined-name
  block is created once (mirrors the existing per-client dedup guard). Key on 
the sanitised, case-folded name, because
  Excel defined names are case-insensitive and the raw values may differ only 
in punctuation/case/whitespace:

  {code:java}
  Set<String> seenProductNames = new HashSet<>();
  for (int i = 0; i < products.size(); i++) {
      String productName = products.get(i).getName()...;
      if 
(!seenProductNames.add(sanitizeName(productName).toUpperCase(Locale.ROOT))) { 
continue; }
      ...
  }
  {code}




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

Reply via email to