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)