Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HCMPRE 1578: Adding facility information for each village in estimation sheet #1311

Open
wants to merge 35 commits into
base: download-estimation-feature
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
8208b6f
hcm v1.5 : dev to master (#855)
kanishq-egov Aug 12, 2024
1ea8b5b
v0.2 admin console merge to master (#849)
nitish-egov Aug 12, 2024
1b1a1d8
mdms config to be taken from devops (#853)
nitish-egov Aug 13, 2024
e3d5238
HLM service request, updated DataTypeEnum (#872)
kanishq-egov Aug 29, 2024
a0e7142
Service request changelog 1.5 (#875)
kanishq-egov Aug 30, 2024
df5b6c9
HCMPRE-424: fixed hrms call from pgr-service
kanishq-egov Sep 9, 2024
1aedebd
HCMPRE-424: updated as per code review comments
kanishq-egov Sep 9, 2024
0fb2c71
Merge pull request #883 from egovernments/hcmpre-424-hrms-fix
sathishp-eGov Sep 9, 2024
1222369
Create branch-name-validator (#960)
kavi-egov Oct 11, 2024
08df5e7
Update branch-name-validator
kavi-egov Oct 11, 2024
11a5800
Rename branch-name-validator to branch-name-validator.yml
kavi-egov Oct 11, 2024
e68c5fb
Merge pull request #965 from egovernments/HCMPRE-0071-feature-name-ms…
sathishp-eGov Oct 11, 2024
1ad04ee
Added census-service in build-config (#990)
tanishi-egov Oct 17, 2024
d4fd0c9
[HCMPRE-658] Refractor resource-estimation-service to resource-genera…
palak-egov Oct 24, 2024
c9f5d73
HCM Admin Console v0.3 Release code changes (#1082)
jagankumar-egov Dec 9, 2024
fd9a00f
HCMPRE-1635 Microplanning v0.1 master merge (#1271)
Priyanka-eGov Dec 12, 2024
8072220
Admin Console & microplanning Patch fixes on project factory (#1276)
jagankumar-egov Dec 12, 2024
3f860f8
Dev (#1235)
naveen-egov Dec 13, 2024
717aeac
Moving PlanValidator and PlanEnricher to respective folders. (#1280)
Priyanka-eGov Dec 13, 2024
9dbb1d7
fixed import issues (#1281)
shashwat-egov Dec 16, 2024
73dfdb9
Adding a column for facility name
tanishi-egov Dec 18, 2024
d0f135e
Adding a column for facility name
tanishi-egov Dec 18, 2024
d8937bd
Adding a column for facility name
tanishi-egov Dec 19, 2024
b364f19
Adding a column for facility name
tanishi-egov Dec 19, 2024
c9d1f61
Adding a column for facility name
tanishi-egov Dec 19, 2024
aca73bb
Adding a column for facility name
tanishi-egov Dec 19, 2024
91cbb52
Adding a column for facility name
tanishi-egov Dec 20, 2024
1217dd7
Adding styling to the column header
tanishi-egov Dec 20, 2024
a4f3c28
Adding styling to the column header
tanishi-egov Dec 20, 2024
5cd6e2f
Adding function comments
tanishi-egov Dec 27, 2024
d465e1b
Adding function comments
tanishi-egov Dec 27, 2024
902b0c1
pull from master
tanishi-egov Jan 3, 2025
3c31167
Revert "pull from master"
tanishi-egov Jan 3, 2025
06779ff
HCMPRE-1801 setting dynamic column width for column headers
Priyanka-eGov Jan 6, 2025
02efb7a
Merge remote-tracking branch 'origin/HCMPRE-1578-new' into HCMPRE-157…
Priyanka-eGov Jan 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.egov.processor.config;


import org.apache.poi.ss.usermodel.IndexedColors;
import org.springframework.stereotype.Component;


Expand Down Expand Up @@ -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.";

Expand Down Expand Up @@ -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_";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.");
Expand All @@ -152,7 +152,7 @@ private void processExcelFile(PlanConfigurationRequest planConfigurationRequest,
*/
private void uploadFileAndIntegrateCampaign(PlanConfigurationRequest planConfigurationRequest,
Object campaignResponse, Workbook workbook,
List<Boundary> campaignBoundaryList, List<CampaignResources> campaignResourcesList) {
List<Boundary> campaignBoundaryList, List<CampaignResources> campaignResourcesList, String filestoreId) {
File fileToUpload = null;
try {
PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration();
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Plan> 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<String, Plan> planMap = planList.stream()
.collect(Collectors.toMap(Plan::getLocality, plan -> plan));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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) {
Expand Down Expand Up @@ -75,7 +81,118 @@ public void processSheetForHeaderLocalization(Sheet sheet, Map<String, String> 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<String, String> 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<String, String> 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<String, String> getBoundaryCodeToFacilityMap(Workbook workbook, PlanConfigurationRequest request, String fileStoreId) {
List<String> 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<Census> 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<String, String> boundaryCodeToFacility, Map<String, String> mappedValues) {
int indexOfFacility = createAssignedFacilityColumn(sheet, assignedFacilityColHeader);
Map<String, Integer> 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;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -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.*;
Expand All @@ -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<String> fetchAttributeNamesFromJson(JsonNode jsonNode)
Expand Down Expand Up @@ -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);
}
}
}