From a08f1d6fb73477d11b834fc149857782e3ec3711 Mon Sep 17 00:00:00 2001 From: Vladyslav Date: Mon, 4 May 2026 16:30:20 +0300 Subject: [PATCH] FINERACT-1341: Fix NumberFormatException in bulk import when loan account number is alphanumeric --- .../guarantor/GuarantorWorkbookPopulator.java | 4 +- .../GuarantorWorkbookPopulatorTest.java | 73 ++++++++++++++++++ .../LoanRepaymentWorkbookPopulatorTest.java | 74 +++++++++++++++++++ 3 files changed, 148 insertions(+), 3 deletions(-) create mode 100644 fineract-provider/src/test/java/org/apache/fineract/infrastructure/bulkimport/populator/guarantor/GuarantorWorkbookPopulatorTest.java create mode 100644 fineract-provider/src/test/java/org/apache/fineract/infrastructure/bulkimport/populator/loanrepayment/LoanRepaymentWorkbookPopulatorTest.java diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/guarantor/GuarantorWorkbookPopulator.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/guarantor/GuarantorWorkbookPopulator.java index ab9326b68a1..48ba00f1fd5 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/guarantor/GuarantorWorkbookPopulator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/guarantor/GuarantorWorkbookPopulator.java @@ -71,7 +71,6 @@ public void populate(Workbook workbook, String dateFormat) { populateSavingsTable(addGuarantorSheet, dateFormat); populateGuarantorRelationshipTypes(addGuarantorSheet, dateFormat); setRules(addGuarantorSheet); - } private void setLayout(Sheet worksheet) { @@ -155,8 +154,7 @@ private void populateLoansTable(Sheet addGuarantorSheet, String dateFormat) { row = addGuarantorSheet.getRow(rowIndex++); } writeString(GuarantorConstants.LOOKUP_CLIENT_NAME_COL, row, loan.getClientName() + "(" + loan.getClientId() + ")"); - writeString(GuarantorConstants.LOOKUP_ACCOUNT_NO_COL, row, - Long.parseLong(loan.getAccountNo()) + "-" + loan.getStatus().getValue()); + writeString(GuarantorConstants.LOOKUP_ACCOUNT_NO_COL, row, loan.getAccountNo() + "-" + loan.getStatus().getValue()); } } diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/bulkimport/populator/guarantor/GuarantorWorkbookPopulatorTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/bulkimport/populator/guarantor/GuarantorWorkbookPopulatorTest.java new file mode 100644 index 00000000000..0e969bfbfa6 --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/bulkimport/populator/guarantor/GuarantorWorkbookPopulatorTest.java @@ -0,0 +1,73 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.bulkimport.populator.guarantor; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import java.util.ArrayList; +import java.util.List; +import org.apache.fineract.infrastructure.bulkimport.populator.ClientSheetPopulator; +import org.apache.fineract.infrastructure.bulkimport.populator.OfficeSheetPopulator; +import org.apache.fineract.portfolio.loanaccount.data.LoanAccountData; +import org.apache.fineract.portfolio.loanaccount.data.LoanStatusEnumData; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Workbook; +import org.junit.jupiter.api.Test; + +class GuarantorWorkbookPopulatorTest { + + private static final LoanStatusEnumData ACTIVE_STATUS = new LoanStatusEnumData(300L, "loanStatusType.active", "Active"); + private static final String DATE_FORMAT = "dd MMMM yyyy"; + + private LoanAccountData loanWithAccountNo(String accountNo) { + return new LoanAccountData().setAccountNo(accountNo).setStatus(ACTIVE_STATUS).setClientName("John Doe").setClientId(1L); + } + + private GuarantorWorkbookPopulator populatorFor(LoanAccountData loan) { + return new GuarantorWorkbookPopulator(new OfficeSheetPopulator(List.of()), new ClientSheetPopulator(List.of(), List.of()), + new ArrayList<>(List.of(loan)), new ArrayList<>(), List.of()); + } + + @Test + void populate_withAlphanumericAccountNumber() { + try (Workbook workbook = new HSSFWorkbook()) { + assertDoesNotThrow(() -> populatorFor(loanWithAccountNo("ABC-001")).populate(workbook, DATE_FORMAT)); + } catch (Exception e) { + // ignore workbook close exceptions + } + } + + @Test + void populate_withMixedAccountNumber() { + try (Workbook workbook = new HSSFWorkbook()) { + assertDoesNotThrow(() -> populatorFor(loanWithAccountNo("001ABC")).populate(workbook, DATE_FORMAT)); + } catch (Exception e) { + // ignore workbook close exceptions + } + } + + @Test + void populate_withNumericAccountNumber() { + try (Workbook workbook = new HSSFWorkbook()) { + assertDoesNotThrow(() -> populatorFor(loanWithAccountNo("000001")).populate(workbook, DATE_FORMAT)); + } catch (Exception e) { + // ignore workbook close exceptions + } + } +} diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/bulkimport/populator/loanrepayment/LoanRepaymentWorkbookPopulatorTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/bulkimport/populator/loanrepayment/LoanRepaymentWorkbookPopulatorTest.java new file mode 100644 index 00000000000..146fc9bc1dc --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/bulkimport/populator/loanrepayment/LoanRepaymentWorkbookPopulatorTest.java @@ -0,0 +1,74 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.bulkimport.populator.loanrepayment; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import org.apache.fineract.infrastructure.bulkimport.constants.LoanRepaymentConstants; +import org.apache.fineract.infrastructure.bulkimport.constants.TemplatePopulateImportConstants; +import org.apache.fineract.infrastructure.bulkimport.populator.ClientSheetPopulator; +import org.apache.fineract.infrastructure.bulkimport.populator.ExtrasSheetPopulator; +import org.apache.fineract.infrastructure.bulkimport.populator.OfficeSheetPopulator; +import org.apache.fineract.portfolio.loanaccount.data.LoanAccountData; +import org.apache.fineract.portfolio.loanaccount.data.LoanStatusEnumData; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.junit.jupiter.api.Test; + +class LoanRepaymentWorkbookPopulatorTest { + + private static final LoanStatusEnumData ACTIVE_STATUS = new LoanStatusEnumData(300L, "loanStatusType.active", "Active"); + private static final String DATE_FORMAT = "dd MMMM yyyy"; + + private LoanAccountData loanWithAccountNo(String accountNo) { + return new LoanAccountData().setAccountNo(accountNo).setStatus(ACTIVE_STATUS).setClientName("John Doe").setClientId(1L) + .setLoanProductName("TestProduct").setPrincipal(BigDecimal.valueOf(10000)); + } + + private LoanRepaymentWorkbookPopulator populatorFor(LoanAccountData loan) { + return new LoanRepaymentWorkbookPopulator(new ArrayList<>(List.of(loan)), new OfficeSheetPopulator(List.of()), + new ClientSheetPopulator(List.of(), List.of()), new ExtrasSheetPopulator(List.of(), List.of(), List.of())); + } + + @Test + void populate_withAlphanumericAccountNumber() throws Exception { + try (Workbook workbook = new HSSFWorkbook()) { + populatorFor(loanWithAccountNo("ABC-001")).populate(workbook, DATE_FORMAT); + + Sheet sheet = workbook.getSheet(TemplatePopulateImportConstants.LOAN_REPAYMENT_SHEET_NAME); + String cellValue = sheet.getRow(1).getCell(LoanRepaymentConstants.LOOKUP_ACCOUNT_NO_COL).getStringCellValue(); + assertEquals("ABC-001-Active", cellValue); + } + } + + @Test + void populate_withNumericAccountNumber() throws Exception { + try (Workbook workbook = new HSSFWorkbook()) { + populatorFor(loanWithAccountNo("00000001")).populate(workbook, DATE_FORMAT); + + Sheet sheet = workbook.getSheet(TemplatePopulateImportConstants.LOAN_REPAYMENT_SHEET_NAME); + String cellValue = sheet.getRow(1).getCell(LoanRepaymentConstants.LOOKUP_ACCOUNT_NO_COL).getStringCellValue(); + assertEquals("00000001-Active", cellValue); + } + } +}