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 #1284

Open
wants to merge 11 commits into
base: download-estimation-feature
Choose a base branch
from
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
@@ -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 @@ -76,6 +82,115 @@ public void processSheetForHeaderLocalization(Sheet sheet, Map<String, String> l
excelStylingUtil.styleCell(headerColumn);
headerColumn.setCellValue(localizationCodeAndMessageMap.get(headerColumnValue));
}

}

/**
* 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) {
tanishi-egov marked this conversation as resolved.
Show resolved Hide resolved
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);
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);
}
}
}