diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java b/health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java index c64a480871..41e9144856 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java @@ -1,7 +1,6 @@ package org.egov.processor.config; -import org.apache.poi.ss.usermodel.IndexedColors; import org.springframework.stereotype.Component; @@ -40,6 +39,9 @@ public class ServiceConstants { public static final String FILE_NOT_FOUND_CODE = "FILE_NOT_FOUND"; public static final String FILE_NOT_FOUND_MESSAGE = "No file with the specified templateIdentifier found - "; + public static final String PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT_CODE = "PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT"; + public static final String PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT_MESSAGE = "Key is not present in json object - "; + public static final String UNABLE_TO_CREATE_ADDITIONAL_DETAILS_CODE = "UNABLE_TO_CREATE_ADDITIONAL_DETAILS"; public static final String UNABLE_TO_CREATE_ADDITIONAL_DETAILS_MESSAGE = "Unable to create additional details for facility creation."; @@ -117,6 +119,8 @@ public class ServiceConstants { public static final String SOURCE_KEY = "source"; public static final String MICROPLAN_SOURCE_KEY = "microplan"; public static final String MICROPLAN_ID_KEY = "microplanId"; + public static final String FACILITY_NAME = "facilityName"; + public static final String HCM_MICROPLAN_SERVING_FACILITY = "HCM_MICROPLAN_SERVING_FACILITY"; //Census additional field constants public static final String UPLOADED_KEY = "UPLOADED_"; diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java b/health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java index ea566f4ed6..2faa00b43f 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java @@ -127,7 +127,7 @@ private void processExcelFile(PlanConfigurationRequest planConfigurationRequest, processSheets(planConfigurationRequest, fileStoreId, campaignResponse, workbook, campaignBoundaryList, dataFormatter); uploadFileAndIntegrateCampaign(planConfigurationRequest, campaignResponse, - workbook, campaignBoundaryList, campaignResourcesList); + workbook, campaignBoundaryList, campaignResourcesList, fileStoreId); } catch (FileNotFoundException e) { log.error("File not found: {}", e.getMessage()); throw new CustomException("FileNotFound", "The specified file was not found."); @@ -152,7 +152,7 @@ private void processExcelFile(PlanConfigurationRequest planConfigurationRequest, */ private void uploadFileAndIntegrateCampaign(PlanConfigurationRequest planConfigurationRequest, Object campaignResponse, Workbook workbook, - List campaignBoundaryList, List campaignResourcesList) { + List campaignBoundaryList, List campaignResourcesList, String filestoreId) { File fileToUpload = null; try { PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); @@ -165,9 +165,12 @@ private void uploadFileAndIntegrateCampaign(PlanConfigurationRequest planConfigu if (planConfig.getStatus().equals(config.getPlanConfigUpdatePlanEstimatesIntoOutputFileStatus()) && config.isIntegrateWithAdminConsole()) { //Upload the processed output file into project factory String uploadedFileStoreId = uploadConvertedFile(fileToUpload, planConfig.getTenantId()); -// campaignIntegrationUtil.updateResourcesInProjectFactory(planConfigurationRequest, uploadedFileStoreId); + campaignIntegrationUtil.updateResourcesInProjectFactory(planConfigurationRequest, uploadedFileStoreId); + outputEstimationGenerationUtil.processOutputFile(workbook, planConfigurationRequest); + // Adding facility information for each boundary code + outputEstimationGenerationUtil.addAssignedFacility(workbook, planConfigurationRequest, filestoreId); //update processed output file into plan configuration file object fileToUpload = convertWorkbookToXls(workbook); diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/EnrichmentUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/EnrichmentUtil.java index d0cd40201f..e543dd062a 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/util/EnrichmentUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/EnrichmentUtil.java @@ -223,10 +223,10 @@ public void enrichsheetWithApprovedPlanEstimates(Sheet sheet, PlanConfigurationR Integer indexOfBoundaryCode = parsingUtil.getIndexOfBoundaryCode(0, parsingUtil.sortColumnByIndex(mapOfColumnNameAndIndex), mappedValues); - //Getting census records for the list of boundaryCodes + //Getting plan records for the list of boundaryCodes List planList = getPlanRecordsForEnrichment(planConfigurationRequest, boundaryCodes); - // Create a map from boundaryCode to Census for quick lookups + // Create a map from boundaryCode to Plan for quick lookups Map planMap = planList.stream() .collect(Collectors.toMap(Plan::getLocality, plan -> plan)); diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/ExcelStylingUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/ExcelStylingUtil.java index c8da424ea1..f24e7bd2fd 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/util/ExcelStylingUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/ExcelStylingUtil.java @@ -42,9 +42,31 @@ public void styleCell(Cell cell) { // Apply the style to the cell cell.setCellStyle(cellStyle); - // Adjust the column width + } + + /** + * Adjusts the column width to fit the content of the given cell, adding padding for readability. + * + * @param cell the cell whose column width is to be adjusted; does nothing if null. + */ + public void adjustColumnWidthForCell(Cell cell) { + if (cell == null) { + return; + } + + Sheet sheet = cell.getSheet(); int columnIndex = cell.getColumnIndex(); - sheet.setColumnWidth(columnIndex, COLUMN_WIDTH * 256); // Width is measured in units of 1/256 of a character + int maxWidth = sheet.getColumnWidth(columnIndex); + + // Calculate the width needed for the current cell content + String cellValue = cell.toString(); // Convert cell content to string + int cellWidth = cellValue.length() * 256; // Approximate width (1/256th of character width) + + // Use the maximum width seen so far, including padding for readability + int padding = 512; // Adjust padding as needed + int newWidth = Math.max(maxWidth, cellWidth + padding); + + sheet.setColumnWidth(columnIndex, newWidth); } /** diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java index d7121157ba..6e4c828e82 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java @@ -1,19 +1,22 @@ package org.egov.processor.util; import org.apache.poi.ss.usermodel.*; -import org.apache.poi.xssf.usermodel.*; import org.egov.processor.web.models.Locale; import org.egov.processor.web.models.LocaleResponse; import org.egov.processor.web.models.PlanConfigurationRequest; -import org.egov.tracer.model.CustomException; +import org.egov.processor.web.models.ResourceMapping; +import org.egov.processor.web.models.census.Census; import org.springframework.stereotype.Component; -import java.awt.Color; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import org.egov.tracer.model.CustomException; -import static org.egov.processor.config.ServiceConstants.*; - +import static org.egov.processor.config.ServiceConstants.FACILITY_NAME; +import static org.egov.processor.config.ServiceConstants.HCM_MICROPLAN_SERVING_FACILITY; @Component public class OutputEstimationGenerationUtil { @@ -24,10 +27,13 @@ public class OutputEstimationGenerationUtil { private ExcelStylingUtil excelStylingUtil; - public OutputEstimationGenerationUtil(LocaleUtil localeUtil, ParsingUtil parsingUtil, ExcelStylingUtil excelStylingUtil) { + private EnrichmentUtil enrichmentUtil; + + public OutputEstimationGenerationUtil(LocaleUtil localeUtil, ParsingUtil parsingUtil, EnrichmentUtil enrichmentUtil, ExcelStylingUtil excelStylingUtil) { this.localeUtil = localeUtil; this.parsingUtil = parsingUtil; this.excelStylingUtil = excelStylingUtil; + this.enrichmentUtil = enrichmentUtil; } public void processOutputFile(Workbook workbook, PlanConfigurationRequest request) { @@ -75,7 +81,118 @@ public void processSheetForHeaderLocalization(Sheet sheet, Map l // Update the cell value with the localized message excelStylingUtil.styleCell(headerColumn); headerColumn.setCellValue(localizationCodeAndMessageMap.get(headerColumnValue)); + excelStylingUtil.adjustColumnWidthForCell(headerColumn); + } + + } + + /** + * This is the main method responsible for adding an assigned facility name column to each sheet in the workbook. + * It iterates through all the sheets, verifies if they are eligible for processing, retrieves required mappings + * and boundary codes, and populates the new column with facility names based on these mappings. + * + * @param workbook the workbook containing the sheets to be processed. + * @param request the plan configuration request containing the resource mapping and other configurations. + * @param fileStoreId the associated file store ID used to filter resource mappings. + */ + public void addAssignedFacility(Workbook workbook, PlanConfigurationRequest request, String fileStoreId) { + LocaleResponse localeResponse = localeUtil.searchLocale(request); + + String assignedFacilityColHeader = localeUtil.localeSearch(localeResponse.getMessages(), HCM_MICROPLAN_SERVING_FACILITY); + assignedFacilityColHeader = assignedFacilityColHeader != null ? assignedFacilityColHeader : HCM_MICROPLAN_SERVING_FACILITY; + + // Creating a map of MappedTo and MappedFrom values from resource mapping + Map mappedValues = request.getPlanConfiguration().getResourceMapping().stream() + .filter(f -> f.getFilestoreId().equals(fileStoreId)) + .collect(Collectors.toMap( + ResourceMapping::getMappedTo, + ResourceMapping::getMappedFrom, + (existing, replacement) -> existing, + LinkedHashMap::new + )); + + // Get the map of boundary code to the facility assigned to that boundary. + Map boundaryCodeToFacility = getBoundaryCodeToFacilityMap(workbook, request, fileStoreId); + + for (int i = 0; i < workbook.getNumberOfSheets(); i++) { + Sheet sheet = workbook.getSheetAt(i); + if (parsingUtil.isSheetAllowedToProcess(request, sheet.getSheetName(), localeResponse)) { + addFacilityNameToSheet(sheet, assignedFacilityColHeader, boundaryCodeToFacility, mappedValues); + } } } + /** + * Collects boundary codes from all eligible sheets in the workbook, fetches census records for these boundaries, + * and maps each boundary code to its assigned facility name obtained from the census data. + * + * @param workbook the workbook containing the sheets. + * @param request the plan configuration request with boundary code details. + * @param fileStoreId the associated file store ID for filtering. + * @return a map of boundary codes to their assigned facility names. + */ + private Map getBoundaryCodeToFacilityMap(Workbook workbook, PlanConfigurationRequest request, String fileStoreId) { + List boundaryCodes = new ArrayList<>(); + + for (int i = 0; i < workbook.getNumberOfSheets(); i++) { + Sheet sheet = workbook.getSheetAt(i); + if (parsingUtil.isSheetAllowedToProcess(request, sheet.getSheetName(), localeUtil.searchLocale(request))) { + boundaryCodes.addAll(enrichmentUtil.getBoundaryCodesFromTheSheet(sheet, request, fileStoreId)); + } + } + + List censusList = enrichmentUtil.getCensusRecordsForEnrichment(request, boundaryCodes); + return censusList.stream() + .collect(Collectors.toMap( + Census::getBoundaryCode, + census -> (String) parsingUtil.extractFieldsFromJsonObject(census.getAdditionalDetails(), FACILITY_NAME))); + } + + /** + * Processes a given sheet by adding a new column for assigned facilities and populating + * each row with the corresponding facility name based on the boundary code. + * + * @param sheet the sheet being processed. + * @param assignedFacilityColHeader the header for the new assigned facility column. + * @param boundaryCodeToFacility the mapping of boundary codes to assigned facilities. + * @param mappedValues a map of 'MappedTo' to 'MappedFrom' values. + */ + private void addFacilityNameToSheet(Sheet sheet, String assignedFacilityColHeader, Map boundaryCodeToFacility, Map mappedValues) { + int indexOfFacility = createAssignedFacilityColumn(sheet, assignedFacilityColHeader); + Map columnNameIndexMap = parsingUtil.getAttributeNameIndexFromExcel(sheet); + int indexOfBoundaryCode = parsingUtil.getIndexOfBoundaryCode(0, parsingUtil.sortColumnByIndex(columnNameIndexMap), mappedValues); + + for (Row row : sheet) { + if (row.getRowNum() == 0 || parsingUtil.isRowEmpty(row)) { + continue; + } + + String boundaryCode = row.getCell(indexOfBoundaryCode).getStringCellValue(); + + Cell facilityCell = row.getCell(indexOfFacility); + if (facilityCell == null) { + facilityCell = row.createCell(indexOfFacility, CellType.STRING); + } + + facilityCell.setCellValue(boundaryCodeToFacility.getOrDefault(boundaryCode, "")); + } + } + + /** + * Adds a new column for the assigned facility name in the provided sheet, styles the header cell, + * and returns the index of the newly created column. + * + * @param sheet the sheet where the column is to be added. + * @param assignedFacilityColHeader the header for the new column. + * @return the index of the newly created column. + */ + private int createAssignedFacilityColumn(Sheet sheet, String assignedFacilityColHeader) { + int indexOfFacility = (int) sheet.getRow(0).getLastCellNum(); + Cell facilityColHeader = sheet.getRow(0).createCell(indexOfFacility, CellType.STRING); + excelStylingUtil.styleCell(facilityColHeader); + facilityColHeader.setCellValue(assignedFacilityColHeader); + excelStylingUtil.adjustColumnWidthForCell(facilityColHeader); + return indexOfFacility; + } } + diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/ParsingUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/ParsingUtil.java index be64bb6853..756252b562 100644 --- a/health-services/resource-generator/src/main/java/org/egov/processor/util/ParsingUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/ParsingUtil.java @@ -17,6 +17,7 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.math.BigDecimal; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.*; @@ -38,11 +39,14 @@ public class ParsingUtil { private MdmsUtil mdmsUtil; - public ParsingUtil(PlanConfigurationUtil planConfigurationUtil, FilestoreUtil filestoreUtil, CalculationUtil calculationUtil, MdmsUtil mdmsUtil) { + private ObjectMapper objectMapper; + + public ParsingUtil(PlanConfigurationUtil planConfigurationUtil, FilestoreUtil filestoreUtil, CalculationUtil calculationUtil, MdmsUtil mdmsUtil, ObjectMapper objectMapper) { this.planConfigurationUtil = planConfigurationUtil; this.filestoreUtil = filestoreUtil; this.calculationUtil = calculationUtil; this.mdmsUtil = mdmsUtil; + this.objectMapper = objectMapper; } public List fetchAttributeNamesFromJson(JsonNode jsonNode) @@ -418,4 +422,37 @@ public boolean isSheetAllowedToProcess(PlanConfigurationRequest planConfiguratio } + /** + * Extracts provided field from the additional details object + * + * @param additionalDetails the additionalDetails object from PlanConfigurationRequest + * @param fieldToExtract the name of the field to be extracted from the additional details + * @return the value of the specified field as a string + * @throws CustomException if the field does not exist + */ + public Object extractFieldsFromJsonObject(Object additionalDetails, String fieldToExtract) { + try { + String jsonString = objectMapper.writeValueAsString(additionalDetails); + JsonNode rootNode = objectMapper.readTree(jsonString); + + JsonNode node = rootNode.get(fieldToExtract); + if (node != null && !node.isNull()) { + + // Check for different types of JSON nodes + if (node.isDouble() || node.isFloat()) { + return BigDecimal.valueOf(node.asDouble()); // Convert Double to BigDecimal + } else if (node.isLong() || node.isInt()) { + return BigDecimal.valueOf(node.asLong()); // Convert Long to BigDecimal + } else if (node.isBoolean()) { + return node.asBoolean(); + } else if (node.isTextual()) { + return node.asText(); + } + } + return null; + } catch (Exception e) { + log.error(e.getMessage() + fieldToExtract); + throw new CustomException(PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT_CODE, PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT_MESSAGE + fieldToExtract); + } + } }