diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/glaccount/domain/GLAccountRepository.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/glaccount/domain/GLAccountRepository.java index a309f066b..cf258bdbf 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/accounting/glaccount/domain/GLAccountRepository.java +++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/glaccount/domain/GLAccountRepository.java @@ -18,9 +18,12 @@ */ package org.apache.fineract.accounting.glaccount.domain; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; public interface GLAccountRepository extends JpaRepository, JpaSpecificationExecutor { // no added behaviour + //adding behaviour to fetch id by glcode for opening balance bulk import + Optional findOneByGlCode(String glCode); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/glaccount/domain/GLAccountRepositoryWrapper.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/glaccount/domain/GLAccountRepositoryWrapper.java index d1973a829..1482c8410 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/accounting/glaccount/domain/GLAccountRepositoryWrapper.java +++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/glaccount/domain/GLAccountRepositoryWrapper.java @@ -40,5 +40,9 @@ public class GLAccountRepositoryWrapper { public GLAccount findOneWithNotFoundDetection(final Long id) { return this.repository.findById(id).orElseThrow(() -> new GLAccountNotFoundException(id)); } + //finding account id by glcode for opening balance bulk import + public GLAccount findOneByGlCodeWithNotFoundDetection(final String glCode) { + return this.repository.findOneByGlCode(glCode).orElseThrow(() -> new GLAccountNotFoundException(glCode)); + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/glaccount/exception/GLAccountNotFoundException.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/glaccount/exception/GLAccountNotFoundException.java index 01b7c6322..1e4c450a8 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/accounting/glaccount/exception/GLAccountNotFoundException.java +++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/glaccount/exception/GLAccountNotFoundException.java @@ -33,4 +33,8 @@ public class GLAccountNotFoundException extends AbstractPlatformResourceNotFound public GLAccountNotFoundException(final Long id, EmptyResultDataAccessException e) { super("error.msg.glaccount.id.invalid", "General Ledger account with identifier " + id + " does not exist ", id, e); } + + public GLAccountNotFoundException(final String glCode) { + super("error.msg.glaccount.code.invalid", "General Ledger account with GlCode " + glCode + " does not exist ", glCode); + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/data/JournalEntryData.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/data/JournalEntryData.java index 3c00ab31c..22865eda0 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/data/JournalEntryData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/data/JournalEntryData.java @@ -90,6 +90,48 @@ public class JournalEntryData { private String routingCode; private String receiptNumber; private String bankNumber; + //for opening bal bulk import + public JournalEntryData(Long officeId, LocalDate transactionDate, String currencyCode, List credits, + List debits, String locale, String dateFormat) { + this.officeId = officeId; + this.dateFormat = dateFormat; + this.locale = locale; + this.transactionDate = transactionDate; + this.currencyCode = currencyCode; + this.credits = credits; + this.debits = debits; + this.rowIndex = null; + this.paymentTypeId = null; + this.accountNumber = null; + this.checkNumber = null; + this.routingCode = null; + this.receiptNumber = null; + this.bankNumber = null; + this.comments = null; + this.id = null; + this.officeName = null; + this.glAccountName = null; + this.glAccountId = null; + this.glAccountCode = null; + this.glAccountType = null; + this.entryType = null; + this.amount = null; + this.currency = null; + this.transactionId = null; + this.manualEntry = null; + this.entityType = null; + this.entityId = null; + this.createdByUserId = null; + this.createdDate = null; + this.createdByUserName = null; + this.reversed = null; + this.referenceNumber = null; + this.officeRunningBalance = null; + this.organizationRunningBalance = null; + this.runningBalanceComputed = null; + this.transactionDetails = null; + + } public static JournalEntryData importInstance(Long officeId, LocalDate transactionDate, String currencyCode, Long paymentTypeId, Integer rowIndex, List credits, List debits, String accountNumber, String checkNumber, @@ -98,6 +140,11 @@ public class JournalEntryData { checkNumber, routingCode, receiptNumber, bankNumber, comments, locale, dateFormat); } + public static JournalEntryData importInstance1(Long officeId, LocalDate transactionDate, String currencyCode, List credits, + List debits, String locale, String dateFormat) { + return new JournalEntryData(officeId, transactionDate, currencyCode, credits, debits, locale, dateFormat); + } + private JournalEntryData(Long officeId, LocalDate transactionDate, String currencyCode, Long paymentTypeId, Integer rowIndex, List credits, List debits, String accountNumber, String checkNumber, String routingCode, String receiptNumber, String bankNumber, String comments, String locale, String dateFormat) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/constants/ChartOfAcountsConstants.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/constants/ChartOfAcountsConstants.java index 59a9032ed..72b54141b 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/constants/ChartOfAcountsConstants.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/constants/ChartOfAcountsConstants.java @@ -34,10 +34,22 @@ public final class ChartOfAcountsConstants { public static final int TAG_COL = 7;// H public static final int TAG_ID_COL = 8;// I public static final int DESCRIPTION_COL = 9;// J - public static final int LOOKUP_ACCOUNT_TYPE_COL = 15;// P - public static final int LOOKUP_ACCOUNT_NAME_COL = 16; // Q - public static final int LOOKUP_ACCOUNT_ID_COL = 17;// R - public static final int LOOKUP_TAG_COL = 18; // S - public static final int LOOKUP_TAG_ID_COL = 19; // T - public static final int STATUS_COL = 20; + //adding for opening balance bulk import + public static final int OFFICE_COL = 10; // K + public static final int OFFICE_COL_ID = 11; // L + public static final int CURRENCY_CODE = 12; // M + public static final int DEBIT_AMOUNT = 13; // N + public static final int CREDIT_AMOUNT = 14; // O + + public static final int LOOKUP_ACCOUNT_TYPE_COL = 18;// S + public static final int LOOKUP_ACCOUNT_NAME_COL = 19; // T + public static final int LOOKUP_ACCOUNT_ID_COL = 20;// U + public static final int LOOKUP_TAG_COL = 21; // V + public static final int LOOKUP_TAG_ID_COL = 22; // W + + //adding for opening balance bulk import + public static final int LOOKUP_OFFICE_COL = 23; // X + public static final int LOOKUP_OFFICE_ID_COL = 24; // Y + + public static final int STATUS_COL = 25; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/chartofaccounts/ChartOfAccountsImportHandler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/chartofaccounts/ChartOfAccountsImportHandler.java index 02d99bc86..c0b264aa7 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/chartofaccounts/ChartOfAccountsImportHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/chartofaccounts/ChartOfAccountsImportHandler.java @@ -19,11 +19,18 @@ package org.apache.fineract.infrastructure.bulkimport.importhandler.chartofaccounts; import com.google.gson.GsonBuilder; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.ZoneId; import java.util.ArrayList; import java.util.List; import org.apache.fineract.accounting.glaccount.data.GLAccountData; +import org.apache.fineract.accounting.glaccount.domain.GLAccount; +import org.apache.fineract.accounting.glaccount.domain.GLAccountRepositoryWrapper; import org.apache.fineract.accounting.glaccount.domain.GLAccountType; import org.apache.fineract.accounting.glaccount.domain.GLAccountUsage; +import org.apache.fineract.accounting.journalentry.data.CreditDebit; +import org.apache.fineract.accounting.journalentry.data.JournalEntryData; import org.apache.fineract.commands.domain.CommandWrapper; import org.apache.fineract.commands.service.CommandWrapperBuilder; import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService; @@ -33,10 +40,13 @@ import org.apache.fineract.infrastructure.bulkimport.data.Count; import org.apache.fineract.infrastructure.bulkimport.importhandler.ImportHandler; import org.apache.fineract.infrastructure.bulkimport.importhandler.ImportHandlerUtils; import org.apache.fineract.infrastructure.bulkimport.importhandler.helper.CodeValueDataIdSerializer; +import org.apache.fineract.infrastructure.bulkimport.importhandler.helper.CurrencyDateCodeSerializer; +import org.apache.fineract.infrastructure.bulkimport.importhandler.helper.DateSerializer; import org.apache.fineract.infrastructure.bulkimport.importhandler.helper.EnumOptionDataIdSerializer; import org.apache.fineract.infrastructure.codes.data.CodeValueData; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.EnumOptionData; +import org.apache.fineract.organisation.monetary.data.CurrencyData; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.IndexedColors; import org.apache.poi.ss.usermodel.Row; @@ -53,24 +63,40 @@ public class ChartOfAccountsImportHandler implements ImportHandler { private static final Logger LOG = LoggerFactory.getLogger(ChartOfAccountsImportHandler.class); private List glAccounts; private Workbook workbook; + private LocalDate transactionDate; + + // for opening bal + int flagForOpBal = 0; + private List gltransaction; + List credits = new ArrayList<>(); + List debits = new ArrayList<>(); + String locale; private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; + private final GLAccountRepositoryWrapper glAccountRepository; @Autowired - public ChartOfAccountsImportHandler(final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) { + public ChartOfAccountsImportHandler(final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService, + GLAccountRepositoryWrapper glAccountRepository) { this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; + this.glAccountRepository = glAccountRepository; } @Override public Count process(Workbook workbook, String locale, String dateFormat) { this.glAccounts = new ArrayList<>(); this.workbook = workbook; + // for opening bal + gltransaction = new ArrayList<>(); + credits = new ArrayList<>(); + debits = new ArrayList<>(); + this.locale = locale; + readExcelFile(); - return importEntity(); + return importEntity(dateFormat); } - public void readExcelFile() { - + private void readExcelFile() { Sheet chartOfAccountsSheet = workbook.getSheet(TemplatePopulateImportConstants.CHART_OF_ACCOUNTS_SHEET_NAME); Integer noOfEntries = ImportHandlerUtils.getNumberOfRows(chartOfAccountsSheet, TemplatePopulateImportConstants.FIRST_COLUMN_INDEX); for (int rowIndex = 1; rowIndex <= noOfEntries; rowIndex++) { @@ -83,6 +109,7 @@ public class ChartOfAccountsImportHandler implements ImportHandler { } private GLAccountData readGlAccounts(Row row) { + String accountType = ImportHandlerUtils.readAsString(ChartOfAcountsConstants.ACCOUNT_TYPE_COL, row); EnumOptionData accountTypeEnum = GLAccountType.fromString(accountType); String accountName = ImportHandlerUtils.readAsString(ChartOfAcountsConstants.ACCOUNT_NAME_COL, row); @@ -109,44 +136,137 @@ public class ChartOfAccountsImportHandler implements ImportHandler { tagIdCodeValueData = new CodeValueData(tagId); } String description = ImportHandlerUtils.readAsString(ChartOfAcountsConstants.DESCRIPTION_COL, row); + if (ImportHandlerUtils.readAsString(ChartOfAcountsConstants.OFFICE_COL, row) != null) { + flagForOpBal = 1; + } else { + flagForOpBal = 0; + } return GLAccountData.importInstance(accountName, parentId, glCode, manualEntriesAllowed, accountTypeEnum, usageEnum, description, tagIdCodeValueData, row.getRowNum()); } - public Count importEntity() { + public Count importEntity(String dateFormat) { Sheet chartOfAccountsSheet = workbook.getSheet(TemplatePopulateImportConstants.CHART_OF_ACCOUNTS_SHEET_NAME); GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(EnumOptionData.class, new EnumOptionDataIdSerializer()); gsonBuilder.registerTypeAdapter(CodeValueData.class, new CodeValueDataIdSerializer()); + gsonBuilder.registerTypeAdapter(LocalDate.class, new DateSerializer(dateFormat)); + gsonBuilder.registerTypeAdapter(CurrencyData.class, new CurrencyDateCodeSerializer()); int successCount = 0; int errorCount = 0; String errorMessage = ""; - for (GLAccountData glAccount : glAccounts) { - try { - String payload = gsonBuilder.create().toJson(glAccount); - final CommandWrapper commandRequest = new CommandWrapperBuilder() // - .createGLAccount() // - .withJson(payload) // - .build(); // - final CommandProcessingResult result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - successCount++; - Cell statusCell = chartOfAccountsSheet.getRow(glAccount.getRowIndex()).createCell(ChartOfAcountsConstants.STATUS_COL); - statusCell.setCellValue(TemplatePopulateImportConstants.STATUS_CELL_IMPORTED); - statusCell.setCellStyle(ImportHandlerUtils.getCellStyle(workbook, IndexedColors.LIGHT_GREEN)); - } catch (RuntimeException ex) { - errorCount++; - LOG.error("Problem occurred in importEntity function", ex); - errorMessage = ImportHandlerUtils.getErrorMessage(ex); - ImportHandlerUtils.writeErrorMessage(chartOfAccountsSheet, glAccount.getRowIndex(), errorMessage, - ChartOfAcountsConstants.STATUS_COL); + + if (glAccounts != null) { + for (GLAccountData glAccount : glAccounts) { + try { + String payload = gsonBuilder.create().toJson(glAccount); + final CommandWrapper commandRequest = new CommandWrapperBuilder() // + .createGLAccount() // + .withJson(payload) // + .build(); // + final CommandProcessingResult result = commandsSourceWritePlatformService.logCommandSource(commandRequest); + successCount++; + Cell statusCell = chartOfAccountsSheet.getRow(glAccount.getRowIndex()).createCell(ChartOfAcountsConstants.STATUS_COL); + statusCell.setCellValue(TemplatePopulateImportConstants.STATUS_CELL_IMPORTED); + statusCell.setCellStyle(ImportHandlerUtils.getCellStyle(workbook, IndexedColors.LIGHT_GREEN)); + } catch (RuntimeException ex) { + errorCount++; + LOG.error("Problem occurred in importEntity function", ex); + errorMessage = ImportHandlerUtils.getErrorMessage(ex); + ImportHandlerUtils.writeErrorMessage(chartOfAccountsSheet, glAccount.getRowIndex(), errorMessage, + ChartOfAcountsConstants.STATUS_COL); + } } + if (flagForOpBal > 0) { + + try { + readExcelFileForOpBal(locale, dateFormat); + JournalEntryData transaction = gltransaction.get(gltransaction.size() - 1); + String payload = gsonBuilder.create().toJson(transaction); + + final CommandWrapper commandRequest = new CommandWrapperBuilder().defineOpeningBalanceForJournalEntry() + .withJson(payload).build(); + final CommandProcessingResult result = commandsSourceWritePlatformService.logCommandSource(commandRequest); + successCount++; + Cell statusCell = chartOfAccountsSheet.getRow(1).createCell(ChartOfAcountsConstants.STATUS_COL); + statusCell.setCellValue(TemplatePopulateImportConstants.STATUS_CELL_IMPORTED); + statusCell.setCellStyle(ImportHandlerUtils.getCellStyle(workbook, IndexedColors.LIGHT_GREEN)); + } catch (RuntimeException ex) { + errorCount++; + LOG.error("Problem occurred in importEntity function", ex); + errorMessage = ImportHandlerUtils.getErrorMessage(ex); + ImportHandlerUtils.writeErrorMessage(chartOfAccountsSheet, 1, errorMessage, ChartOfAcountsConstants.STATUS_COL); + } + } + chartOfAccountsSheet.setColumnWidth(ChartOfAcountsConstants.STATUS_COL, TemplatePopulateImportConstants.SMALL_COL_SIZE); + ImportHandlerUtils.writeString(ChartOfAcountsConstants.STATUS_COL, + chartOfAccountsSheet.getRow(TemplatePopulateImportConstants.ROWHEADER_INDEX), + TemplatePopulateImportConstants.STATUS_COLUMN_HEADER); + return Count.instance(successCount, errorCount); } + chartOfAccountsSheet.setColumnWidth(ChartOfAcountsConstants.STATUS_COL, TemplatePopulateImportConstants.SMALL_COL_SIZE); ImportHandlerUtils.writeString(ChartOfAcountsConstants.STATUS_COL, chartOfAccountsSheet.getRow(TemplatePopulateImportConstants.ROWHEADER_INDEX), TemplatePopulateImportConstants.STATUS_COLUMN_HEADER); return Count.instance(successCount, errorCount); + } + // for opening balance + public void readExcelFileForOpBal(final String locale, final String dateFormat) { + + Sheet chartOfAccountsSheet = workbook.getSheet(TemplatePopulateImportConstants.CHART_OF_ACCOUNTS_SHEET_NAME); + Integer noOfEntries = ImportHandlerUtils.getNumberOfRows(chartOfAccountsSheet, TemplatePopulateImportConstants.FIRST_COLUMN_INDEX); + for (int rowIndex = 1; rowIndex <= noOfEntries; rowIndex++) { + Row row; + row = chartOfAccountsSheet.getRow(rowIndex); + + // + JournalEntryData journalEntry = null; + journalEntry = readAddJournalEntries(row, locale, dateFormat); + gltransaction.add(journalEntry); + } + + } + + // for opening balance + private JournalEntryData readAddJournalEntries(Row row, String locale, String dateFormat) { + LocalDate transactionDateCheck = LocalDate.now(ZoneId.systemDefault()); + if (transactionDateCheck != null) { + transactionDate = transactionDateCheck; + } + + String officeName = ImportHandlerUtils.readAsString(ChartOfAcountsConstants.OFFICE_COL, row); + Long officeId = ImportHandlerUtils.readAsLong(ChartOfAcountsConstants.OFFICE_COL_ID, row); + + String currencyCode = ImportHandlerUtils.readAsString(ChartOfAcountsConstants.CURRENCY_CODE, row); + String accountToBeDebitedCredited = ImportHandlerUtils.readAsString(ChartOfAcountsConstants.ACCOUNT_NAME_COL, row); + String glCode = ImportHandlerUtils.readAsString(ChartOfAcountsConstants.GL_CODE_COL, row); + GLAccount glAccount = this.glAccountRepository.findOneByGlCodeWithNotFoundDetection(glCode); + Long glAccountIdToDebitedCredited = glAccount.getId(); + if (glAccountIdToDebitedCredited == null) { + throw new RuntimeException("Account does not exist"); + } + + // String credit = + // readAsString(JournalEntryConstants.GL_ACCOUNT_ID_CREDIT_COL, row); + // String debit = + // readAsString(JournalEntryConstants.GL_ACCOUNT_ID_DEBIT_COL, row); + + if (accountToBeDebitedCredited != null) { + if (ImportHandlerUtils.readAsLong(ChartOfAcountsConstants.CREDIT_AMOUNT, row) != null) { + credits.add(new CreditDebit(glAccountIdToDebitedCredited, + BigDecimal.valueOf(ImportHandlerUtils.readAsLong(ChartOfAcountsConstants.CREDIT_AMOUNT, row)))); + + } else if (ImportHandlerUtils.readAsLong(ChartOfAcountsConstants.DEBIT_AMOUNT, row) != null) { + debits.add(new CreditDebit(glAccountIdToDebitedCredited, + BigDecimal.valueOf(ImportHandlerUtils.readAsLong(ChartOfAcountsConstants.DEBIT_AMOUNT, row)))); + } + } + + return JournalEntryData.importInstance1(officeId, transactionDate, currencyCode, credits, debits, locale, dateFormat); + + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/chartofaccounts/ChartOfAccountsWorkbook.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/chartofaccounts/ChartOfAccountsWorkbook.java index 576e589a4..68a775d06 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/chartofaccounts/ChartOfAccountsWorkbook.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/chartofaccounts/ChartOfAccountsWorkbook.java @@ -29,6 +29,8 @@ import org.apache.fineract.accounting.glaccount.domain.GLAccountUsage; import org.apache.fineract.infrastructure.bulkimport.constants.ChartOfAcountsConstants; import org.apache.fineract.infrastructure.bulkimport.constants.TemplatePopulateImportConstants; import org.apache.fineract.infrastructure.bulkimport.populator.AbstractWorkbookPopulator; +import org.apache.fineract.organisation.monetary.data.CurrencyData; +import org.apache.fineract.organisation.office.data.OfficeData; import org.apache.poi.hssf.usermodel.HSSFDataValidationHelper; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.ss.SpreadsheetVersion; @@ -47,12 +49,16 @@ public class ChartOfAccountsWorkbook extends AbstractWorkbookPopulator { private static final Logger LOG = LoggerFactory.getLogger(ChartOfAccountsWorkbook.class); private final List glAccounts; + private final List offices; // adding opening balance office tag + private List currencies; // adding opening balance currency code private Map> accountTypeToAccountNameAndTag; private Map accountTypeToBeginEndIndexesofAccountNames; private List accountTypesNoDuplicatesList; - public ChartOfAccountsWorkbook(List glAccounts) { + public ChartOfAccountsWorkbook(List glAccounts, List offices, List currencies) { this.glAccounts = glAccounts; + this.offices = offices; // opening balance offices names + this.currencies = currencies; // opening balance currency codes } @Override @@ -63,6 +69,7 @@ public class ChartOfAccountsWorkbook extends AbstractWorkbookPopulator { setLookupTable(chartOfAccountsSheet); setRules(chartOfAccountsSheet); setDefaults(chartOfAccountsSheet); + } private void setAccountTypeToAccountNameAndTag() { @@ -84,6 +91,16 @@ public class ChartOfAccountsWorkbook extends AbstractWorkbookPopulator { } } + private String[] getCurrency() { + String[] currencyCode = new String[currencies.size()]; + int currencyIndex = 0; + for (CurrencyData currencies : currencies) { + currencyCode[currencyIndex] = currencies.code(); + currencyIndex++; + } + return currencyCode; + } + private void setRules(Sheet chartOfAccountsSheet) { CellRangeAddressList accountTypeRange = new CellRangeAddressList(1, SpreadsheetVersion.EXCEL97.getLastRowIndex(), ChartOfAcountsConstants.ACCOUNT_TYPE_COL, ChartOfAcountsConstants.ACCOUNT_TYPE_COL); @@ -95,9 +112,13 @@ public class ChartOfAccountsWorkbook extends AbstractWorkbookPopulator { ChartOfAcountsConstants.PARENT_COL, ChartOfAcountsConstants.PARENT_COL); CellRangeAddressList tagRange = new CellRangeAddressList(1, SpreadsheetVersion.EXCEL97.getLastRowIndex(), ChartOfAcountsConstants.TAG_COL, ChartOfAcountsConstants.TAG_COL); + CellRangeAddressList officeNameRange = new CellRangeAddressList(1, SpreadsheetVersion.EXCEL97.getLastRowIndex(), + ChartOfAcountsConstants.OFFICE_COL, ChartOfAcountsConstants.OFFICE_COL); // validation for opening bal office column + CellRangeAddressList currencyCodeRange = new CellRangeAddressList(1, SpreadsheetVersion.EXCEL97.getLastRowIndex(), + ChartOfAcountsConstants.CURRENCY_CODE, ChartOfAcountsConstants.CURRENCY_CODE);// validation for currency code for opening balance DataValidationHelper validationHelper = new HSSFDataValidationHelper((HSSFSheet) chartOfAccountsSheet); - setNames(chartOfAccountsSheet, accountTypesNoDuplicatesList); + setNames(chartOfAccountsSheet, accountTypesNoDuplicatesList, offices); DataValidationConstraint accountTypeConstraint = validationHelper .createExplicitListConstraint(new String[] { GLAccountType.ASSET.toString(), GLAccountType.LIABILITY.toString(), @@ -108,38 +129,48 @@ public class ChartOfAccountsWorkbook extends AbstractWorkbookPopulator { DataValidationConstraint parentConstraint = validationHelper .createFormulaListConstraint("INDIRECT(CONCATENATE(\"AccountName_\",$A1))"); DataValidationConstraint tagConstraint = validationHelper.createFormulaListConstraint("INDIRECT(CONCATENATE(\"Tags_\",$A1))"); + DataValidationConstraint officeNameConstraint = validationHelper.createFormulaListConstraint("Office"); + DataValidationConstraint currencyCodeConstraint = validationHelper.createExplicitListConstraint(getCurrency()); DataValidation accountTypeValidation = validationHelper.createValidation(accountTypeConstraint, accountTypeRange); DataValidation accountUsageValidation = validationHelper.createValidation(accountUsageConstraint, accountUsageRange); DataValidation manualEntriesValidation = validationHelper.createValidation(booleanConstraint, manualEntriesAllowedRange); DataValidation parentValidation = validationHelper.createValidation(parentConstraint, parentRange); DataValidation tagValidation = validationHelper.createValidation(tagConstraint, tagRange); + DataValidation officeNameValidation = validationHelper.createValidation(officeNameConstraint, officeNameRange); + DataValidation currencyCodeValidation = validationHelper.createValidation(currencyCodeConstraint, currencyCodeRange); chartOfAccountsSheet.addValidationData(accountTypeValidation); chartOfAccountsSheet.addValidationData(accountUsageValidation); chartOfAccountsSheet.addValidationData(manualEntriesValidation); chartOfAccountsSheet.addValidationData(parentValidation); chartOfAccountsSheet.addValidationData(tagValidation); + chartOfAccountsSheet.addValidationData(officeNameValidation); + chartOfAccountsSheet.addValidationData(currencyCodeValidation); } - private void setNames(Sheet chartOfAccountsSheet, List accountTypesNoDuplicatesList) { + private void setNames(Sheet chartOfAccountsSheet, List accountTypesNoDuplicatesList, List offices) { Workbook chartOfAccountsWorkbook = chartOfAccountsSheet.getWorkbook(); for (Integer i = 0; i < accountTypesNoDuplicatesList.size(); i++) { Name tags = chartOfAccountsWorkbook.createName(); Integer[] tagValueBeginEndIndexes = accountTypeToBeginEndIndexesofAccountNames.get(i); if (accountTypeToBeginEndIndexesofAccountNames != null) { setSanitized(tags, "Tags_" + accountTypesNoDuplicatesList.get(i)); - tags.setRefersToFormula(TemplatePopulateImportConstants.CHART_OF_ACCOUNTS_SHEET_NAME + "!$S$" + tagValueBeginEndIndexes[0] - + ":$S$" + tagValueBeginEndIndexes[1]); + tags.setRefersToFormula(TemplatePopulateImportConstants.CHART_OF_ACCOUNTS_SHEET_NAME + "!$V$" + tagValueBeginEndIndexes[0] + + ":$V$" + tagValueBeginEndIndexes[1]); } Name accountNames = chartOfAccountsWorkbook.createName(); Integer[] accountNamesBeginEndIndexes = accountTypeToBeginEndIndexesofAccountNames.get(i); if (accountNamesBeginEndIndexes != null) { setSanitized(accountNames, "AccountName_" + accountTypesNoDuplicatesList.get(i)); - accountNames.setRefersToFormula(TemplatePopulateImportConstants.CHART_OF_ACCOUNTS_SHEET_NAME + "!$Q$" - + accountNamesBeginEndIndexes[0] + ":$Q$" + accountNamesBeginEndIndexes[1]); + accountNames.setRefersToFormula(TemplatePopulateImportConstants.CHART_OF_ACCOUNTS_SHEET_NAME + "!$T$" + + accountNamesBeginEndIndexes[0] + ":$T$" + accountNamesBeginEndIndexes[1]); } } + Name officeGroup = chartOfAccountsWorkbook.createName(); + officeGroup.setNameName("Office"); + officeGroup.setRefersToFormula(TemplatePopulateImportConstants.CHART_OF_ACCOUNTS_SHEET_NAME + "!$X$2:$X$" + (offices.size() + 1)); + } private void setDefaults(Sheet worksheet) { @@ -150,11 +181,15 @@ public class ChartOfAccountsWorkbook extends AbstractWorkbookPopulator { row = worksheet.createRow(rowNo); } writeFormula(ChartOfAcountsConstants.PARENT_ID_COL, row, - "IF(ISERROR(VLOOKUP($E" + (rowNo + 1) + ",$Q$2:$R$" + (glAccounts.size() + 1) + ",2,FALSE))," + "\"\",(VLOOKUP($E" - + (rowNo + 1) + ",$Q$2:$R$" + (glAccounts.size() + 1) + ",2,FALSE)))"); + "IF(ISERROR(VLOOKUP($E" + (rowNo + 1) + ",$T$2:$U$" + (glAccounts.size() + 1) + ",2,FALSE))," + "\"\",(VLOOKUP($E" + + (rowNo + 1) + ",$T$2:$U$" + (glAccounts.size() + 1) + ",2,FALSE)))"); writeFormula(ChartOfAcountsConstants.TAG_ID_COL, row, - "IF(ISERROR(VLOOKUP($H" + (rowNo + 1) + ",$S$2:$T$" + (glAccounts.size() + 1) + ",2,FALSE))," + "\"\",(VLOOKUP($H" - + (rowNo + 1) + ",$S$2:$T$" + (glAccounts.size() + 1) + ",2,FALSE)))"); + "IF(ISERROR(VLOOKUP($H" + (rowNo + 1) + ",$V$2:$W$" + (glAccounts.size() + 1) + ",2,FALSE))," + "\"\",(VLOOKUP($H" + + (rowNo + 1) + ",$V$2:$W$" + (glAccounts.size() + 1) + ",2,FALSE)))"); + //auto populate office id for bulk import of opening balance + writeFormula(ChartOfAcountsConstants.OFFICE_COL_ID, row, + "IF(ISERROR(VLOOKUP($K" + (rowNo + 1) + ",$X$2:$Y$" + (offices.size() + 1) + ",2,FALSE)),\"\",(VLOOKUP($K" + + (rowNo + 1) + ",$X$2:$Y$" + (offices.size() + 1) + ",2,FALSE)))"); } } catch (Exception e) { LOG.error("Problem occurred in setDefaults function", e); @@ -201,9 +236,29 @@ public class ChartOfAccountsWorkbook extends AbstractWorkbookPopulator { accountTypeIndex++; } } + //opening balance lookup table of offices + startIndex = 1; + rowIndex = 1; + for (OfficeData office : offices) { + startIndex = rowIndex + 1; + if (chartOfAccountsSheet.getRow(rowIndex) != null) { + Row row = chartOfAccountsSheet.getRow(rowIndex); + writeString(ChartOfAcountsConstants.LOOKUP_OFFICE_COL, row, office.name()); + writeLong(ChartOfAcountsConstants.LOOKUP_OFFICE_ID_COL, row, office.getId()); + rowIndex++; + + } else { + Row row = chartOfAccountsSheet.createRow(rowIndex); + writeString(ChartOfAcountsConstants.LOOKUP_OFFICE_COL, row, office.name()); + writeLong(ChartOfAcountsConstants.LOOKUP_OFFICE_ID_COL, row, office.getId()); + rowIndex++; + } + + } } private void setLayout(Sheet chartOfAccountsSheet) { + Row rowHeader = chartOfAccountsSheet.createRow(TemplatePopulateImportConstants.ROWHEADER_INDEX); chartOfAccountsSheet.setColumnWidth(ChartOfAcountsConstants.ACCOUNT_TYPE_COL, TemplatePopulateImportConstants.SMALL_COL_SIZE); chartOfAccountsSheet.setColumnWidth(ChartOfAcountsConstants.ACCOUNT_NAME_COL, TemplatePopulateImportConstants.SMALL_COL_SIZE); @@ -216,6 +271,11 @@ public class ChartOfAccountsWorkbook extends AbstractWorkbookPopulator { chartOfAccountsSheet.setColumnWidth(ChartOfAcountsConstants.TAG_COL, TemplatePopulateImportConstants.SMALL_COL_SIZE); chartOfAccountsSheet.setColumnWidth(ChartOfAcountsConstants.TAG_ID_COL, TemplatePopulateImportConstants.SMALL_COL_SIZE); chartOfAccountsSheet.setColumnWidth(ChartOfAcountsConstants.DESCRIPTION_COL, TemplatePopulateImportConstants.EXTRALARGE_COL_SIZE); + chartOfAccountsSheet.setColumnWidth(ChartOfAcountsConstants.OFFICE_COL, TemplatePopulateImportConstants.MEDIUM_COL_SIZE); + chartOfAccountsSheet.setColumnWidth(ChartOfAcountsConstants.OFFICE_COL_ID, TemplatePopulateImportConstants.SMALL_COL_SIZE); + chartOfAccountsSheet.setColumnWidth(ChartOfAcountsConstants.CURRENCY_CODE, TemplatePopulateImportConstants.MEDIUM_COL_SIZE); + chartOfAccountsSheet.setColumnWidth(ChartOfAcountsConstants.DEBIT_AMOUNT, TemplatePopulateImportConstants.SMALL_COL_SIZE); + chartOfAccountsSheet.setColumnWidth(ChartOfAcountsConstants.CREDIT_AMOUNT, TemplatePopulateImportConstants.SMALL_COL_SIZE); chartOfAccountsSheet.setColumnWidth(ChartOfAcountsConstants.LOOKUP_ACCOUNT_TYPE_COL, TemplatePopulateImportConstants.SMALL_COL_SIZE); chartOfAccountsSheet.setColumnWidth(ChartOfAcountsConstants.LOOKUP_ACCOUNT_NAME_COL, @@ -223,6 +283,9 @@ public class ChartOfAccountsWorkbook extends AbstractWorkbookPopulator { chartOfAccountsSheet.setColumnWidth(ChartOfAcountsConstants.LOOKUP_ACCOUNT_ID_COL, TemplatePopulateImportConstants.MEDIUM_COL_SIZE); chartOfAccountsSheet.setColumnWidth(ChartOfAcountsConstants.LOOKUP_TAG_COL, TemplatePopulateImportConstants.SMALL_COL_SIZE); chartOfAccountsSheet.setColumnWidth(ChartOfAcountsConstants.LOOKUP_TAG_ID_COL, TemplatePopulateImportConstants.SMALL_COL_SIZE); + //adding lookup for opening balance bulk import + chartOfAccountsSheet.setColumnWidth(ChartOfAcountsConstants.LOOKUP_OFFICE_COL, TemplatePopulateImportConstants.MEDIUM_COL_SIZE); + chartOfAccountsSheet.setColumnWidth(ChartOfAcountsConstants.LOOKUP_OFFICE_ID_COL, TemplatePopulateImportConstants.SMALL_COL_SIZE); writeString(ChartOfAcountsConstants.ACCOUNT_TYPE_COL, rowHeader, "Account Type*"); writeString(ChartOfAcountsConstants.GL_CODE_COL, rowHeader, "GL Code *"); @@ -234,11 +297,22 @@ public class ChartOfAccountsWorkbook extends AbstractWorkbookPopulator { writeString(ChartOfAcountsConstants.TAG_COL, rowHeader, "Tag"); writeString(ChartOfAcountsConstants.TAG_ID_COL, rowHeader, "Tag Id"); writeString(ChartOfAcountsConstants.DESCRIPTION_COL, rowHeader, "Description *"); + //adding data for opening balance bulk import + writeString(ChartOfAcountsConstants.OFFICE_COL, rowHeader, "Parent Office for Opening Balance"); + writeString(ChartOfAcountsConstants.OFFICE_COL_ID, rowHeader, "Parent Office Code Opening Balance"); + writeString(ChartOfAcountsConstants.CURRENCY_CODE, rowHeader, "Currency Code"); + writeString(ChartOfAcountsConstants.DEBIT_AMOUNT, rowHeader, "Debit Amount"); + writeString(ChartOfAcountsConstants.CREDIT_AMOUNT, rowHeader, "Credit Amount"); + writeString(ChartOfAcountsConstants.LOOKUP_ACCOUNT_TYPE_COL, rowHeader, "Lookup Account type"); writeString(ChartOfAcountsConstants.LOOKUP_TAG_COL, rowHeader, "Lookup Tag"); writeString(ChartOfAcountsConstants.LOOKUP_TAG_ID_COL, rowHeader, "Lookup Tag Id"); writeString(ChartOfAcountsConstants.LOOKUP_ACCOUNT_NAME_COL, rowHeader, "Lookup Account name *"); writeString(ChartOfAcountsConstants.LOOKUP_ACCOUNT_ID_COL, rowHeader, "Lookup Account Id"); + //adding lookup for opening balance bulk import + writeString(ChartOfAcountsConstants.LOOKUP_OFFICE_COL, rowHeader, "Lookup Office Name"); + writeString(ChartOfAcountsConstants.LOOKUP_OFFICE_ID_COL, rowHeader, "Lookup Office Id"); } + } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/service/BulkImportWorkbookPopulatorServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/service/BulkImportWorkbookPopulatorServiceImpl.java index 4d0a59d17..0bff74555 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/service/BulkImportWorkbookPopulatorServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/service/BulkImportWorkbookPopulatorServiceImpl.java @@ -196,7 +196,7 @@ public class BulkImportWorkbookPopulatorServiceImpl implements BulkImportWorkboo } else if (entityType.trim().equalsIgnoreCase(GlobalEntityType.OFFICES.toString())) { populator = populateOfficeWorkbook(); } else if (entityType.trim().equalsIgnoreCase(GlobalEntityType.CHART_OF_ACCOUNTS.toString())) { - populator = populateChartOfAccountsWorkbook(); + populator = populateChartOfAccountsWorkbook(officeId); } else if (entityType.trim().equalsIgnoreCase(GlobalEntityType.STAFF.toString())) { populator = populateStaffWorkbook(officeId); } else if (entityType.trim().equalsIgnoreCase(GlobalEntityType.SHARE_ACCOUNTS.toString())) { @@ -503,10 +503,12 @@ public class BulkImportWorkbookPopulatorServiceImpl implements BulkImportWorkboo return new OfficeWorkbookPopulator(offices); } - private WorkbookPopulator populateChartOfAccountsWorkbook() { + private WorkbookPopulator populateChartOfAccountsWorkbook(Long officeId) { this.context.authenticatedUser().validateHasReadPermission(TemplatePopulateImportConstants.GL_ACCOUNT_ENTITY_TYPE); List glAccounts = fetchGLAccounts(); - return new ChartOfAccountsWorkbook(glAccounts); + List offices = fetchOffices(null); + return new ChartOfAccountsWorkbook(glAccounts, offices, + (List) this.currencyReadPlatformService.retrieveAllowedCurrencies()); } private WorkbookPopulator populateStaffWorkbook(Long officeId) {