Repository: egovernments/health-campaign-services
Pull request #1482: HCMPRE-2525 Draft API changes
Author: login: Priyanka-eGov
Created: 2025-04-02T11:19:08Z | Merged: 2025-04-08T06:07:02Z



<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

- **New Features**
  - Enabled asynchronous processing to improve overall performance.
  - Introduced a new web endpoint for initiating draft plan creation.
  - Enhanced error messaging to provide clearer feedback during file processing.
  - Improved Excel file handling for generating refined draft outputs.
  - Streamlined integration with campaign services for optimized resource estimation.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/Main.java b/health-services/resource-generator/src/main/java/org/egov/processor/Main.java
index bee96b9f016..a67aede4609 100644
--- a/health-services/resource-generator/src/main/java/org/egov/processor/Main.java
+++ b/health-services/resource-generator/src/main/java/org/egov/processor/Main.java
@@ -6,10 +6,12 @@
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.Import;
+import org.springframework.scheduling.annotation.EnableAsync;
 
 @Import({ TracerConfiguration.class })
 @SpringBootApplication
 @ComponentScan(basePackages = { "org.egov.processor", "org.egov.processor.web.controllers" , "org.egov.processor.config"})
+@EnableAsync
 public class Main {
 
 
diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/config/ErrorConstants.java b/health-services/resource-generator/src/main/java/org/egov/processor/config/ErrorConstants.java
index 63134da58d9..e12406ddea6 100644
--- a/health-services/resource-generator/src/main/java/org/egov/processor/config/ErrorConstants.java
+++ b/health-services/resource-generator/src/main/java/org/egov/processor/config/ErrorConstants.java
@@ -57,7 +57,13 @@ public class ErrorConstants {
     public static final String ERROR_PROCESSING_DATA_FROM_MDMS = "Exception occurred while processing data from mdms ";
     public static final String ERROR_WHILE_FETCHING_FROM_PLAN_SERVICE_FOR_LOCALITY = "Exception occurred while fetching plan configuration from plan service for Locality ";
     public static final String ERROR_WHILE_PUSHING_TO_PLAN_SERVICE_FOR_LOCALITY = "Exception occurred while fetching plan configuration from plan service for Locality ";
-    public static final String ERROR_WHILE_SEARCHING_CAMPAIGN = "Exception occurred while searching/updating campaign.";
+
+    public static final String ERROR_FETCHING_CAMPAIGN_DETAILS_CODE = "ERROR_FETCHING_CAMPAIGN_DETAILS";
+    public static final String ERROR_FETCHING_CAMPAIGN_DETAILS_MESSAGE = "Error while fetching campaign details: ";
+
+    public static final String NO_CAMPAIGN_FOUND_CODE = "NO_CAMPAIGN_FOUND";
+    public static final String NO_CAMPAIGN_FOUND_MESSAGE = "No campaign found for the provide campaign Id";
+
     public static final String ERROR_WHILE_DATA_CREATE_CALL = "Exception occurred while creating data for campaign - ";
     public static final String ERROR_WHILE_CALLING_MICROPLAN_API =
             "Unexpected error while calling fetch from Microplan API for plan config Id: ";
@@ -66,5 +72,6 @@ public class ErrorConstants {
     public static final String ERROR_CONVERTING_TO_EXCEL_FILE = "Exception occurred while converting workbook to XLS: ";
     public static final String ERROR_SAVING_EXCEL_FILE = "Exception occurred while saving XLS file: ";
 
-
+    public static final String WORKBOOK_READ_ERROR_CODE = "WORKBOOK_READ_ERROR";
+    public static final String WORKBOOK_READ_ERROR_MESSAGE = "Failed to read the workbook from file.";
 }
\ No newline at end of file
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 5199485aa9b..e6f018ccec4 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
@@ -41,13 +41,13 @@ public class ServiceConstants {
     public static final String FILE_TEMPLATE_IDENTIFIER_ESTIMATIONS_IN_PROGRESS = "EstimationsInprogress";
     public static final String FILE_TEMPLATE_IDENTIFIER_ESTIMATIONS = "Estimations";
     public static final String FILE_TEMPLATE_IDENTIFIER_POPULATION = "Population";
+    public static final String FILE_TEMPLATE_IDENTIFIER_DRAFT_INPROGRESS = "DraftInprogress";
+    public static final String FILE_TEMPLATE_IDENTIFIER_DRAFT_COMPLETE = "DraftComplete";
     public static final String FILE_TEMPLATE_IDENTIFIER_BOUNDARY = "boundaryWithTarget";
     public static final String FILE_TEMPLATE_IDENTIFIER_FACILITY = "Facilities";
     public static final String INPUT_IS_NOT_VALID = "File does not contain valid input for row ";
 
     //Mdms constants and masters
-    public static final String MDMS_SCHEMA_TYPE =  "type";
-    public static final String MDMS_SCHEMA_SECTION =  "section";
     public static final String MDMS_SCHEMA_TITLE =  "title";
     public static final String MDMS_PLAN_MODULE_NAME = "hcm-microplanning";
     public static final String MDMS_MASTER_SCHEMAS = "Schemas";
@@ -84,7 +84,6 @@ public class ServiceConstants {
     public static final String VALIDATE_NUMBER_REGX = "^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$";
     public static final String VALIDATE_BOOLEAN_REGX = "^(?i)(true|false)$";
     
-    public static final String FILE_TEMPLATE = "Facilities";
     public static final String HIERARCHYTYPE_REPLACER = "{hierarchyType}";
     public static final String FILE_EXTENSION = "excel";
     
@@ -131,4 +130,7 @@ public class ServiceConstants {
     public static final boolean FREEZE_CELL = true; // Controls whether cells should be locked for editing
     public static final int COLUMN_WIDTH = 40; //Default column width in characters (1-255)
     public static final int COLUMN_PADDING = 512;
-}
+
+    public static final String DRAFT_STATUS = "DRAFT";
+    public static final String DRAFT_RESPONSE = "Draft processing started successfully.";
+ }
diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/service/DraftService.java b/health-services/resource-generator/src/main/java/org/egov/processor/service/DraftService.java
new file mode 100644
index 00000000000..54d151bad9b
--- /dev/null
+++ b/health-services/resource-generator/src/main/java/org/egov/processor/service/DraftService.java
@@ -0,0 +1,128 @@
+package org.egov.processor.service;
+
+import org.apache.poi.ss.usermodel.Workbook;
+import org.egov.processor.util.*;
+import org.egov.processor.web.models.*;
+import org.egov.processor.web.models.campaignManager.CampaignResponse;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.egov.processor.config.ServiceConstants.FILE_TEMPLATE_IDENTIFIER_POPULATION;
+import static org.egov.processor.web.models.File.InputFileTypeEnum.EXCEL;
+
+@Service
+public class DraftService {
+
+    private PlanConfigurationUtil planConfigurationUtil;
+
+    private ExcelParser excelParser;
+
+    private ParsingUtil parsingUtil;
+
+    private PlanUtil planUtil;
+
+    private CampaignIntegrationUtil campaignIntegrationUtil;
+
+    private MdmsUtil mdmsUtil;
+
+    private LocaleUtil localeUtil;
+
+    private EnrichmentUtil enrichmentUtil;
+
+    private OutputEstimationGenerationUtil outputEstimationGenerationUtil;
+
+
+    public DraftService(PlanConfigurationUtil planConfigurationUtil, ExcelParser excelParser, ParsingUtil parsingUtil, PlanUtil planUtil, CampaignIntegrationUtil campaignIntegrationUtil, MdmsUtil mdmsUtil, LocaleUtil localeUtil, EnrichmentUtil enrichmentUtil, OutputEstimationGenerationUtil outputEstimationGenerationUtil) {
+        this.planConfigurationUtil = planConfigurationUtil;
+        this.excelParser = excelParser;
+        this.parsingUtil = parsingUtil;
+        this.planUtil = planUtil;
+        this.campaignIntegrationUtil = campaignIntegrationUtil;
+        this.mdmsUtil = mdmsUtil;
+        this.localeUtil = localeUtil;
+        this.enrichmentUtil = enrichmentUtil;
+        this.outputEstimationGenerationUtil = outputEstimationGenerationUtil;
+    }
+
+    /**
+     * Creates a draft plan by retrieving and processing relevant data.
+     * - Searches for the plan configuration based on the draft request.
+     * - Retrieves and processes the population template file.
+     * - Fetches campaign, locale, and MDMS data.
+     * - Performs resource mapping enrichment and calculations.
+     * - Processes and localizes the workbook before generating the output file.
+     * - Uploads the processed file and updates the plan configuration with the new fileStoreId.
+     *
+     * @param draftRequest the request containing details for draft plan creation.
+     */
+    @Async
+    public void createDraftPlans(DraftRequest draftRequest) {
+        // Retrieve Plan Configuration
+        List<PlanConfiguration> planConfigurationList = planConfigurationUtil.search(planConfigurationUtil.buildPlanConfigurationSearchRequest(draftRequest));
+        PlanConfigurationRequest request = PlanConfigurationRequest.builder()
+                .requestInfo(draftRequest.getRequestInfo())
+                .planConfiguration(planConfigurationList.get(0))
+                .build();
+
+        // Get filestoreId for population template
+        String fileStoreId = getFilestoreIdForPopulationTemplate(request.getPlanConfiguration());
+
+        // Retrieve data and perform actions
+        Workbook workbook = excelParser.getWorkbookFromFilestoreId(fileStoreId, request.getPlanConfiguration().getTenantId());
+        CampaignResponse campaign = campaignIntegrationUtil.performCampaignSearch(request);
+        LocaleResponse localeResponse = localeUtil.searchLocale(request);
+        Object mdmsData = mdmsUtil.fetchMdmsData(request.getRequestInfo(), request.getPlanConfiguration().getTenantId());
+
+        // Perform operations and enrichment
+        planConfigurationUtil.orderPlanConfigurationOperations(request);
+        enrichmentUtil.enrichResourceMapping(request, localeResponse, campaign.getCampaign().get(0).getProjectType(), fileStoreId);
+
+        // Prepare data for processing
+        Map<String, Object> attributeNameVsDataTypeMap = excelParser.prepareAttributeVsIndexMap(fileStoreId, campaign, request.getPlanConfiguration(), mdmsData);
+        List<String> boundaryCodeList = excelParser.getBoundaryCodeList(request, campaign);
+
+        // Fetch common constants mdms data
+        Map<String, Object> mdmsDataForCommonConstants = mdmsUtil.fetchMdmsDataForCommonConstants(
+                request.getRequestInfo(),
+                request.getPlanConfiguration().getTenantId()
+        );
+
+        // Process the workbook
+        workbook.forEach(excelWorkbookSheet -> {
+            if (outputEstimationGenerationUtil.isSheetAllowedToProcess(excelWorkbookSheet.getSheetName(), localeResponse, mdmsDataForCommonConstants)) {
+                excelParser.processRows(request, excelWorkbookSheet, fileStoreId, attributeNameVsDataTypeMap, boundaryCodeList, new HashMap<>(), Boolean.TRUE);
+            }});
+
+        // Process output file - handle localisation
+        outputEstimationGenerationUtil.processDraftOutputFile(workbook, request);
+
+        // Generate output and upload the file
+        java.io.File fileToUpload = parsingUtil.convertWorkbookToXls(workbook);
+        String uploadedFileStoreId = excelParser.uploadConvertedFile(fileToUpload, request.getPlanConfiguration().getTenantId());
+
+        // Update Plan Configuration request with the uploaded fileStoreId
+        planConfigurationUtil.setOrAddFileForDraft(request, uploadedFileStoreId, EXCEL);
+        planUtil.update(request);
+    }
+
+    /**
+     * Retrieves the filestoreId of the active population template file from the given plan configuration.
+     *
+     * @param planConfiguration the plan configuration containing file details.
+     * @return the filestoreId of the active population template, or null if not found.
+     */
+    private String getFilestoreIdForPopulationTemplate(PlanConfiguration planConfiguration) {
+        return planConfiguration.getFiles().stream()
+                .filter(File::getActive)
+                .filter(file -> file.getTemplateIdentifier().equalsIgnoreCase(FILE_TEMPLATE_IDENTIFIER_POPULATION))
+                .map(File::getFilestoreId)
+                .findFirst()
+                .orElse(null);
+    }
+
+
+}
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 46754301400..29b77ace675 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
@@ -15,7 +15,6 @@
 import org.egov.processor.web.models.*;
 import org.egov.processor.web.models.boundary.BoundarySearchResponse;
 import org.egov.processor.web.models.boundary.EnrichedBoundary;
-import org.egov.processor.web.models.campaignManager.Boundary;
 import org.egov.processor.web.models.campaignManager.CampaignResponse;
 import org.egov.processor.web.models.census.Census;
 import org.egov.processor.web.models.mdmsV2.MixedStrategyOperationLogic;
@@ -38,7 +37,6 @@
 
 import static org.egov.processor.config.ErrorConstants.*;
 import static org.egov.processor.config.ServiceConstants.*;
-import static org.egov.processor.config.ServiceConstants.BOUNDARY_CODE;
 import static org.egov.processor.web.models.File.InputFileTypeEnum.EXCEL;
 
 @Slf4j
@@ -209,8 +207,7 @@ private void processSheets(PlanConfigurationRequest request, String fileStoreId,
 				request.getPlanConfiguration().getTenantId());
 		planConfigurationUtil.orderPlanConfigurationOperations(request);
 		enrichmentUtil.enrichResourceMapping(request, localeResponse, campaignResponse.getCampaign().get(0).getProjectType(), fileStoreId);
-		Map<String, Object> attributeNameVsDataTypeMap = prepareAttributeVsIndexMap(request,
-				fileStoreId, campaignResponse, request.getPlanConfiguration(), mdmsData);
+		Map<String, Object> attributeNameVsDataTypeMap = prepareAttributeVsIndexMap(fileStoreId, campaignResponse, request.getPlanConfiguration(), mdmsData);
 
 		List<String> boundaryCodeList = getBoundaryCodeList(request, campaignResponse);
 		Map<String, String> mappedValues = request.getPlanConfiguration().getResourceMapping().stream()
@@ -379,22 +376,21 @@ private Map<String, Boolean> fetchFixedPostDetails(PlanConfigurationRequest requ
 	 *                                 rows.
 	 * @param sheet                    The Excel sheet containing the data to be
 	 *                                 processed.
-	 * @param dataFormatter            The data formatter for formatting cell
-	 *                                 values.
 	 * @param fileStoreId              The ID of the file in the file store.
-	 * @param campaignBoundaryList     The list of campaign boundaries to be
-	 *                                 updated.
 	 * @param attributeNameVsDataTypeMap Mapping of attribute names to their data types.
 	 * @param boundaryCodeList List of boundary codes.
-	 * @throws IOException If an I/O error occurs.
 	 */
-	private void processRows(PlanConfigurationRequest planConfigurationRequest, Sheet sheet, DataFormatter dataFormatter,
-							 String fileStoreId, List<Boundary> campaignBoundaryList, Map<String, Object> attributeNameVsDataTypeMap,
-							 List<String> boundaryCodeList, Map<String, Object> boundaryCodeToCensusAdditionalDetails) {
+	protected void processRows(PlanConfigurationRequest planConfigurationRequest, Sheet sheet,
+							 String fileStoreId, Map<String, Object> attributeNameVsDataTypeMap,
+							 List<String> boundaryCodeList, Map<String, Object> boundaryCodeToCensusAdditionalDetails,
+							   boolean skipFixedPost) {
 
 		// Create a Map of Boundary Code to Facility's fixed post detail.
-		Map<String, Boolean> boundaryCodeToFixedPostMap = fetchFixedPostDetails(planConfigurationRequest);
-		performRowLevelCalculations(planConfigurationRequest, sheet, dataFormatter, fileStoreId, campaignBoundaryList, attributeNameVsDataTypeMap, boundaryCodeList, boundaryCodeToFixedPostMap, boundaryCodeToCensusAdditionalDetails);
+		// Only fetch fixed post details if the flag is false
+		Map<String, Boolean> boundaryCodeToFixedPostMap = skipFixedPost
+				? Collections.emptyMap() // Provide an empty map if skipping
+				: fetchFixedPostDetails(planConfigurationRequest);
+		performRowLevelCalculations(planConfigurationRequest, sheet, fileStoreId, attributeNameVsDataTypeMap, boundaryCodeList, boundaryCodeToFixedPostMap, boundaryCodeToCensusAdditionalDetails, skipFixedPost);
 	}
 
 	private void processRowsForCensusRecords(PlanConfigurationRequest planConfigurationRequest, Sheet sheet, String fileStoreId, Map<String, Object> attributeNameVsDataTypeMap, List<String> boundaryCodeList, String hierarchyType) {
@@ -438,8 +434,8 @@ private void processRowsForCensusRecords(PlanConfigurationRequest planConfigurat
 	 * @param campaign The campaign response object containing campaign details.
 	 * @return A list of boundary codes corresponding to the specified hierarchy type and tenant ID.
 	 */
-	private List<String> getBoundaryCodeList(PlanConfigurationRequest planConfigurationRequest,
-			CampaignResponse campaign) {
+    List<String> getBoundaryCodeList(PlanConfigurationRequest planConfigurationRequest,
+                                     CampaignResponse campaign) {
 		BoundarySearchResponse boundarySearchResponse = boundaryUtil.search(planConfigurationRequest.getPlanConfiguration().getTenantId(),
 				campaign.getCampaign().get(0).getHierarchyType(), planConfigurationRequest);
 		List<String> boundaryList = new ArrayList<>();
@@ -450,15 +446,13 @@ private List<String> getBoundaryCodeList(PlanConfigurationRequest planConfigurat
 	/**
 	 * Prepares a mapping of attribute names to their corresponding indices or data types based on configuration and MDMS data.
 	 *
-	 * @param planConfigurationRequest The request containing configuration details including tenant ID.
 	 * @param fileStoreId The ID of the uploaded file in the file store.
 	 * @param campaign The campaign response object containing campaign details.
 	 * @param planConfig The configuration details specific to the plan.
 	 * @return A map of attribute names to their corresponding indices or data types.
 	 */
 
-	private Map<String, Object> prepareAttributeVsIndexMap(PlanConfigurationRequest planConfigurationRequest,
-			String fileStoreId, CampaignResponse campaign, PlanConfiguration planConfig, Object mdmsData) {
+	public Map<String, Object> prepareAttributeVsIndexMap(String fileStoreId, CampaignResponse campaign, PlanConfiguration planConfig, Object mdmsData) {
 		org.egov.processor.web.models.File file = planConfig.getFiles().stream()
 				.filter(f -> f.getFilestoreId().equalsIgnoreCase(fileStoreId)).findFirst().get();
         return mdmsUtil.filterMasterData(mdmsData.toString(), campaign.getCampaign().get(0).getProjectType());
@@ -472,16 +466,13 @@ private Map<String, Object> prepareAttributeVsIndexMap(PlanConfigurationRequest
 	 *
 	 * @param planConfigurationRequest The request containing configuration details including tenant ID.
 	 * @param sheet The sheet from which rows are processed.
-	 * @param dataFormatter The data formatter for formatting cell values.
 	 * @param fileStoreId The ID of the uploaded file in the file store.
-	 * @param campaignBoundaryList List of boundary objects related to the campaign.
 	 * @param attributeNameVsDataTypeMap Mapping of attribute names to their data types.
 	 * @param boundaryCodeList List of boundary codes.
 	 */
 	private void performRowLevelCalculations(PlanConfigurationRequest planConfigurationRequest, Sheet sheet,
-			DataFormatter dataFormatter, String fileStoreId, List<Boundary> campaignBoundaryList,
-			Map<String, Object> attributeNameVsDataTypeMap, List<String> boundaryCodeList,
-											 Map<String, Boolean> boundaryCodeToFixedPostMap, Map<String, Object> boundaryCodeToCensusAdditionalDetails)  {
+			String fileStoreId,	Map<String, Object> attributeNameVsDataTypeMap, List<String> boundaryCodeList,
+											 Map<String, Boolean> boundaryCodeToFixedPostMap, Map<String, Object> boundaryCodeToCensusAdditionalDetails, boolean skipFixedPost)  {
 		Row firstRow = null;
 		PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration();
 		Map<String, String> mappedValues = planConfig.getResourceMapping().stream()
@@ -515,8 +506,16 @@ private void performRowLevelCalculations(PlanConfigurationRequest planConfigurat
 
 			// Get Boundary Code for the current row.
 			String boundaryCode = row.getCell(indexOfBoundaryCode).getStringCellValue();
-			mixedStrategyUtil.processResultMap(resultMap, planConfig.getOperations(), mixedStrategyUtil.getCategoriesNotAllowed(boundaryCodeToFixedPostMap.get(boundaryCode), planConfig, mixedStrategyOperationLogicList));
-			planUtil.create(planConfigurationRequest, feature, resultMap, boundaryCodeToCensusAdditionalDetails);
+
+			// Skip processing the result map for mixed strategies if the flag is true
+			if (!skipFixedPost) {
+				mixedStrategyUtil.processResultMap(resultMap, planConfig.getOperations(),
+						mixedStrategyUtil.getCategoriesNotAllowed(boundaryCodeToFixedPostMap.get(boundaryCode),
+								planConfig, mixedStrategyOperationLogicList));
+			}
+
+			if(!planConfigurationRequest.getPlanConfiguration().getStatus().equalsIgnoreCase(DRAFT_STATUS))
+				planUtil.create(planConfigurationRequest, feature, resultMap, boundaryCodeToCensusAdditionalDetails);
 
 		}
 	}
@@ -565,7 +564,7 @@ private void performCalculationsOnOperations(Sheet sheet, PlanConfiguration plan
 	 * @param tenantId      The tenant ID for the file upload.
 	 * @return The file store  ID of the uploaded file, or null if an error occurred.
 	 */
-	private String uploadConvertedFile(File convertedFile, String tenantId) {
+    String uploadConvertedFile(File convertedFile, String tenantId) {
 		if (convertedFile != null) {
 			return filestoreUtil.uploadFile(convertedFile, tenantId);
 		}
@@ -867,5 +866,32 @@ public List<String> getAllBoundaryPresentforHierarchyType(List<EnrichedBoundary>
 		return boundaryList;
 	}
 
+	/**
+	 * Retrieves a Workbook from the given filestore ID and tenant ID.
+	 *
+	 * @param filestoreId the filestore identifier
+	 * @param tenantId the tenant identifier
+	 * @return the Workbook extracted from the filestore
+	 * @throws CustomException if the file is not found or cannot be read
+	 */
+	public Workbook getWorkbookFromFilestoreId(String filestoreId, String tenantId) {
+		File file = parsingUtil.convertByteArrayToFile(
+				filestoreUtil.getFileByteArray(tenantId, filestoreId),
+				ServiceConstants.FILE_EXTENSION
+		);
+
+		if (file == null || !file.exists()) {
+			log.error(FILE_NOT_FOUND_LOG, filestoreId, tenantId);
+			throw new CustomException(FILE_NOT_FOUND_CODE,
+					String.format(FILE_NOT_FOUND_MESSAGE, filestoreId, tenantId));
+		}
+
+		try {
+			return new XSSFWorkbook(file);
+		} catch (IOException | InvalidFormatException e) {
+			log.error("Error while reading the workbook from file: {}", file.getAbsolutePath(), e);
+			throw new CustomException(WORKBOOK_READ_ERROR_CODE, WORKBOOK_READ_ERROR_MESSAGE);
+		}
+	}
 
 }
\ No newline at end of file
diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java
index 762fad3be05..5c5344288ad 100644
--- a/health-services/resource-generator/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java
+++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java
@@ -12,7 +12,11 @@
 import org.egov.tracer.model.CustomException;
 import org.springframework.stereotype.Component;
 
-import java.util.*;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 import static org.egov.processor.config.ErrorConstants.*;
 import static org.egov.processor.config.ServiceConstants.*;
@@ -31,6 +35,26 @@ public CampaignIntegrationUtil(ServiceRequestRepository serviceRequestRepository
 		this.mapper = mapper;
 	}
 
+	/**
+	 * Performs a campaign search based on the provided plan configuration request.
+	 * This method builds a campaign search request using the integration utility,
+	 * fetches the search result from the service request repository, and returns it.
+	 *
+	 * @param planConfigurationRequest The request object containing configuration details for the campaign search.
+	 * @return The Campaign response object containing the result of the campaign search.
+	 */
+    public CampaignResponse performCampaignSearch(PlanConfigurationRequest planConfigurationRequest) {
+		try {
+			CampaignSearchRequest campaignRequest = buildCampaignRequestForSearch(planConfigurationRequest);
+            Object response = serviceRequestRepository.fetchResult(new StringBuilder(
+                    config.getProjectFactoryHostEndPoint() + config.getCampaignIntegrationSearchEndPoint()), campaignRequest);
+            return mapper.convertValue(response, CampaignResponse.class);
+		} catch (Exception e) {
+			log.error(ERROR_FETCHING_CAMPAIGN_DETAILS_MESSAGE + planConfigurationRequest.getPlanConfiguration().getCampaignId(), e);
+			throw new CustomException(ERROR_FETCHING_CAMPAIGN_DETAILS_CODE, ERROR_FETCHING_CAMPAIGN_DETAILS_MESSAGE);
+		}
+	}
+
 	/**
 	 * Updates resources in the Project Factory by calling an external API with the given plan configuration
 	 * request and file store ID. Logs the operation status.
@@ -147,21 +171,6 @@ public CampaignSearchRequest buildCampaignRequestForSearch(PlanConfigurationRequ
 
 	}
 
-	/**
-	 * Performs a campaign search based on the provided plan configuration request.
-	 * This method builds a campaign search request using the integration utility,
-	 * fetches the search result from the service request repository, and returns it.
-	 *
-	 * @param planConfigurationRequest The request object containing configuration details for the campaign search.
-	 * @return The response object containing the result of the campaign search.
-	 */
-	public CampaignResponse performCampaignSearch(PlanConfigurationRequest planConfigurationRequest) {
-		CampaignSearchRequest campaignRequest = buildCampaignRequestForSearch(planConfigurationRequest);
-		Object response = serviceRequestRepository.fetchResult(new StringBuilder(
-				config.getProjectFactoryHostEndPoint() + config.getCampaignIntegrationSearchEndPoint()), campaignRequest);
-		return mapper.convertValue(response, CampaignResponse.class);
-	}
-
 	/**
 	 * Creates a JSON node containing additional details for facility creation.
 	 *
diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/FilestoreUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/FilestoreUtil.java
index 6ee884cc45a..6d53434219c 100644
--- a/health-services/resource-generator/src/main/java/org/egov/processor/util/FilestoreUtil.java
+++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/FilestoreUtil.java
@@ -1,21 +1,9 @@
 package org.egov.processor.util;
 
-import static org.egov.processor.config.ErrorConstants.NOT_ABLE_TO_CONVERT_MULTIPARTFILE_TO_BYTESTREAM_CODE;
-import static org.egov.processor.config.ErrorConstants.NOT_ABLE_TO_CONVERT_MULTIPARTFILE_TO_BYTESTREAM_MESSAGE;
-import static org.egov.processor.config.ServiceConstants.FILES;
-import static org.egov.processor.config.ServiceConstants.FILESTORE_ID;
-import static org.egov.processor.config.ServiceConstants.FILESTORE_ID_REPLACER;
-import static org.egov.processor.config.ServiceConstants.MICROPLANNING_MODULE;
-import static org.egov.processor.config.ServiceConstants.MODULE;
-import static org.egov.processor.config.ServiceConstants.TENANTID;
-import static org.egov.processor.config.ServiceConstants.TENANTID_REPLACER;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.util.Arrays;
-import java.util.List;
-
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
 import org.egov.processor.config.Configuration;
 import org.egov.processor.repository.ServiceRequestRepository;
 import org.egov.tracer.model.CustomException;
@@ -29,11 +17,15 @@
 import org.springframework.util.MultiValueMap;
 import org.springframework.web.multipart.MultipartFile;
 
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.Arrays;
+import java.util.List;
 
-import lombok.extern.slf4j.Slf4j;
+import static org.egov.processor.config.ErrorConstants.NOT_ABLE_TO_CONVERT_MULTIPARTFILE_TO_BYTESTREAM_CODE;
+import static org.egov.processor.config.ErrorConstants.NOT_ABLE_TO_CONVERT_MULTIPARTFILE_TO_BYTESTREAM_MESSAGE;
+import static org.egov.processor.config.ServiceConstants.*;
 
 @Component
 @Slf4j
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 de0262da037..3f40d7c4a08 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
@@ -51,12 +51,46 @@ public OutputEstimationGenerationUtil(LocaleUtil localeUtil, ParsingUtil parsing
      * @param filestoreId the identifier of the file store for additional processing requirements
      */
     public void processOutputFile(Workbook workbook, PlanConfigurationRequest request, String filestoreId) {
+        // 1. Remove readme sheets and localise column headers
+        filterAndLocalizeWorkbook(workbook, request);
+
+        // 2. Adding facility information for each boundary code
+        for(Sheet sheet: workbook) {
+            addAssignedFacility(sheet, request, filestoreId);
+        }
+
+        // 3. Add new columns to the sheet, if any.
+        for(Sheet sheet: workbook) {
+            addNewColumns(sheet, request);
+        }
+
+    }
+
+    /**
+     * Processes an output Excel workbook by removing unnecessary sheets, localizing header columns
+     * for each boundary code. The configuration for processing
+     * is based on the provided PlanConfigurationRequest.
+     *
+     * @param workbook   the Excel workbook to process
+     * @param request    the PlanConfigurationRequest containing processing configuration
+     */
+    public void processDraftOutputFile(Workbook workbook, PlanConfigurationRequest request) {
+        // Remove readme sheets and localise column headers
+        filterAndLocalizeWorkbook(workbook, request);
+
+        // Add new columns to the sheet, if any.
+        for(Sheet sheet: workbook) {
+            addNewColumns(sheet, request);
+        }
+    }
+
+    private void filterAndLocalizeWorkbook(Workbook workbook, PlanConfigurationRequest request) {
         LocaleResponse localeResponse = localeUtil.searchLocale(request);
         Map<String, Object> mdmsDataForCommonConstants = mdmsUtil.fetchMdmsDataForCommonConstants(
                 request.getRequestInfo(),
                 request.getPlanConfiguration().getTenantId());
 
-        // 1. removing readme sheet
+        // 1. Remove unwanted sheets
         for (int i = workbook.getNumberOfSheets() - 1; i >= 0; i--) {
             Sheet sheet = workbook.getSheetAt(i);
             if (!isSheetAllowedToProcess(sheet.getSheetName(), localeResponse, mdmsDataForCommonConstants)) {
@@ -65,18 +99,10 @@ public void processOutputFile(Workbook workbook, PlanConfigurationRequest reques
         }
 
         // 2. Stylize and localize output column headers
-        for(Sheet sheet: workbook) {
+        for (Sheet sheet : workbook) {
             processSheetForHeaderLocalization(sheet, localeResponse);
         }
 
-        // 3. Adding facility information for each boundary code
-        for(Sheet sheet: workbook) {
-            addAssignedFacility(sheet, request, filestoreId);
-        }
-
-        for(Sheet sheet: workbook) {
-            addNewColumns(sheet, request);
-        }
     }
 
     /**
diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java
index f4a3060f9c5..a9da09257c0 100644
--- a/health-services/resource-generator/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java
+++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java
@@ -6,6 +6,7 @@
 import org.egov.processor.repository.ServiceRequestRepository;
 import org.egov.processor.web.models.*;
 import org.springframework.stereotype.Component;
+import org.springframework.util.ObjectUtils;
 
 import java.util.ArrayList;
 import java.util.Comparator;
@@ -13,6 +14,8 @@
 import java.util.List;
 
 import static org.egov.processor.config.ErrorConstants.ERROR_WHILE_FETCHING_FROM_PLAN_SERVICE;
+import static org.egov.processor.config.ServiceConstants.FILE_TEMPLATE_IDENTIFIER_DRAFT_COMPLETE;
+import static org.egov.processor.config.ServiceConstants.FILE_TEMPLATE_IDENTIFIER_DRAFT_INPROGRESS;
 
 @Component
 @Slf4j
@@ -63,4 +66,63 @@ public List<PlanConfiguration> search(PlanConfigurationSearchRequest planConfigu
     public void orderPlanConfigurationOperations(PlanConfigurationRequest planConfigurationRequest) {
         planConfigurationRequest.getPlanConfiguration().getOperations().sort(Comparator.comparingInt(Operation::getExecutionOrder));
     }
+
+    /**
+     * Builds a PlanConfigurationSearchRequest using information from the DraftRequest,
+     * including the plan configuration ID, tenant ID, and request info.
+     *
+     * @param draftRequest the DraftRequest containing search details
+     * @return a PlanConfigurationSearchRequest with the search criteria and request info
+     */
+    public PlanConfigurationSearchRequest buildPlanConfigurationSearchRequest(DraftRequest draftRequest) {
+        PlanConfigurationSearchCriteria searchCriteria = PlanConfigurationSearchCriteria.builder()
+                .id(draftRequest.getDraftDetails().getPlanConfigurationId())
+                .tenantId(draftRequest.getDraftDetails().getTenantId())
+                .build();
+
+        return PlanConfigurationSearchRequest.builder()
+                .requestInfo(draftRequest.getRequestInfo())
+                .planConfigurationSearchCriteria(searchCriteria)
+                .build();
+    }
+
+    /**
+     * Sets the filestore ID for the file with template identifier "FILE_TEMPLATE_IDENTIFIER_DRAFT_INPROGRESS".
+     * If the file exists, the filestore ID is updated. If the file does not exist, a new file is added
+     * with the specified filestore ID and input file type.
+     *
+     * @param planConfigurationRequest the plan configuration request containing the list of files
+     * @param fileStoreId the filestore ID to set or add
+     * @param inputFileType the input file type for the new file if added
+     */
+    public void setOrAddFileForDraft(PlanConfigurationRequest planConfigurationRequest, String fileStoreId,
+                                                     File.InputFileTypeEnum inputFileType) {
+        List<File> files = planConfigurationRequest.getPlanConfiguration().getFiles();
+
+        // Check if file with the specified templateIdentifier exists
+        File existingFile = files.stream()
+                .filter(file -> FILE_TEMPLATE_IDENTIFIER_DRAFT_INPROGRESS.equals(file.getTemplateIdentifier()))
+                .findFirst()
+                .orElse(null);
+
+        if (!ObjectUtils.isEmpty(existingFile)) {
+            // If the file exists, update the filestoreId and change template identifier to Draft Complete
+            existingFile.setFilestoreId(fileStoreId);
+            existingFile.setTemplateIdentifier(FILE_TEMPLATE_IDENTIFIER_DRAFT_COMPLETE);
+        } else {
+            // If the file doesn't exist, add a new file
+            File estimationFile = File.builder()
+                    .filestoreId(fileStoreId)
+                    .inputFileType(inputFileType)
+                    .templateIdentifier(FILE_TEMPLATE_IDENTIFIER_DRAFT_COMPLETE)
+                    .active(true)
+                    .build();
+            files.add(estimationFile);
+        }
+
+        // Set workflow to null to ensure plan configuration is processed as a new entity without workflow state
+        planConfigurationRequest.getPlanConfiguration().setWorkflow(null);
+    }
+
+
 }
diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/controllers/DraftController.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/controllers/DraftController.java
new file mode 100644
index 00000000000..6a3b19b5a84
--- /dev/null
+++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/controllers/DraftController.java
@@ -0,0 +1,27 @@
+package org.egov.processor.web.controllers;
+
+import jakarta.validation.Valid;
+import org.egov.processor.service.DraftService;
+import org.egov.processor.web.models.DraftRequest;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+import static org.egov.processor.config.ServiceConstants.DRAFT_RESPONSE;
+
+@Controller
+public class DraftController {
+
+    private DraftService draftService;
+
+    public DraftController(DraftService draftService) {
+        this.draftService = draftService;
+    }
+
+    @PostMapping("/drafts")
+    public ResponseEntity<String> createDraftMicroplan(@RequestBody @Valid DraftRequest draftRequest) {
+        draftService.createDraftPlans(draftRequest);
+        return ResponseEntity.accepted().body(DRAFT_RESPONSE);
+    }
+}
diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/controllers/FileController.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/controllers/FileController.java
index fac9d74d4d1..22ed0604611 100644
--- a/health-services/resource-generator/src/main/java/org/egov/processor/web/controllers/FileController.java
+++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/controllers/FileController.java
@@ -2,7 +2,6 @@
 
 
 import com.fasterxml.jackson.databind.ObjectMapper;
-import java.util.List;
 import org.egov.common.contract.request.RequestInfo;
 import org.egov.processor.service.ExcelParser;
 import org.egov.processor.util.ParsingUtil;
@@ -13,9 +12,11 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.stereotype.Controller;
+
+import java.util.List;
 
 
 @Controller
diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/DraftDetails.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/DraftDetails.java
new file mode 100644
index 00000000000..8f8747d726f
--- /dev/null
+++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/DraftDetails.java
@@ -0,0 +1,20 @@
+package org.egov.processor.web.models;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+@Data
+public class DraftDetails {
+    @JsonProperty("planConfigurationId")
+    @Valid
+    @Size(min = 2, max = 64)
+    private String planConfigurationId = null;
+
+    @JsonProperty("tenantId")
+    @NotNull
+    @Size(min = 2, max = 64)
+    private String tenantId = null;
+}
diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/DraftRequest.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/DraftRequest.java
new file mode 100644
index 00000000000..7a5d8946341
--- /dev/null
+++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/DraftRequest.java
@@ -0,0 +1,17 @@
+package org.egov.processor.web.models;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import jakarta.validation.Valid;
+import lombok.Data;
+import org.egov.common.contract.request.RequestInfo;
+
+@Data
+public class DraftRequest {
+    @JsonProperty("RequestInfo")
+    @Valid
+    private RequestInfo requestInfo;
+
+    @JsonProperty("DraftDetails")
+    @Valid
+    private DraftDetails draftDetails;
+}


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 9**

<details>
<summary>📜 Review details</summary>

**Configuration used: .coderabbit.yaml**
**Review profile: ASSERTIVE**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 5b875095cbfdb6ed60a75fb9a68b57bf5fac4fbd and fb866ed5d23bfe2df0ff495f59a4e390bdb3d733.

</details>

<details>
<summary>📒 Files selected for processing (14)</summary>

* `health-services/resource-generator/src/main/java/org/egov/processor/Main.java` (1 hunks)
* `health-services/resource-generator/src/main/java/org/egov/processor/config/ErrorConstants.java` (1 hunks)
* `health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java` (2 hunks)
* `health-services/resource-generator/src/main/java/org/egov/processor/service/DraftService.java` (1 hunks)
* `health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java` (8 hunks)
* `health-services/resource-generator/src/main/java/org/egov/processor/service/ResourceEstimationService.java` (1 hunks)
* `health-services/resource-generator/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java` (1 hunks)
* `health-services/resource-generator/src/main/java/org/egov/processor/util/FilestoreUtil.java` (2 hunks)
* `health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java` (2 hunks)
* `health-services/resource-generator/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java` (2 hunks)
* `health-services/resource-generator/src/main/java/org/egov/processor/web/controllers/DraftController.java` (1 hunks)
* `health-services/resource-generator/src/main/java/org/egov/processor/web/controllers/FileController.java` (1 hunks)
* `health-services/resource-generator/src/main/java/org/egov/processor/web/models/DraftDetails.java` (1 hunks)
* `health-services/resource-generator/src/main/java/org/egov/processor/web/models/DraftRequest.java` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧠 Learnings (1)</summary>

<details>
<summary>health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java (2)</summary>

```
Learnt from: Priyanka-eGov
PR: egovernments/health-campaign-services#1340
File: health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java:448-449
Timestamp: 2025-04-02T09:49:04.306Z
Learning: In the health-campaign-services codebase, boundary codes in ExcelParser are pre-validated in the validateRows function before being used, which ensures they cannot be null or empty when accessed later in the code flow.
```

```
Learnt from: tanishi-egov
PR: egovernments/health-campaign-services#1340
File: health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java:395-395
Timestamp: 2025-04-02T09:49:04.306Z
Learning: In the ExcelParser class, null check for MDMS data is not required in prepareAttributeVsIndexMap() method as the exception is already handled during MDMS data fetching in mdmsUtil.fetchMdmsData().
```

</details>

</details><details>
<summary>🧬 Code Definitions (5)</summary>

<details>
<summary>health-services/resource-generator/src/main/java/org/egov/processor/web/models/DraftDetails.java (1)</summary><blockquote>

<details>
<summary>health-services/resource-generator/src/main/java/org/egov/processor/web/models/DraftRequest.java (1)</summary>

* `Data` (8-17)

</details>

</blockquote></details>
<details>
<summary>health-services/resource-generator/src/main/java/org/egov/processor/web/models/DraftRequest.java (1)</summary><blockquote>

<details>
<summary>health-services/resource-generator/src/main/java/org/egov/processor/web/models/DraftDetails.java (1)</summary>

* `Data` (9-20)

</details>

</blockquote></details>
<details>
<summary>health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java (4)</summary><blockquote>

<details>
<summary>health-services/resource-generator/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java (1)</summary>

* `Component` (20-128)

</details>
<details>
<summary>health-services/resource-generator/src/main/java/org/egov/processor/util/ExcelStylingUtil.java (1)</summary>

* `Component` (12-114)

</details>
<details>
<summary>health-services/resource-generator/src/main/java/org/egov/processor/util/MixedStrategyUtil.java (1)</summary>

* `Component` (24-121)

</details>
<details>
<summary>health-services/resource-generator/src/main/java/org/egov/processor/util/BoundaryUtil.java (1)</summary>

* `Component` (17-66)

</details>

</blockquote></details>
<details>
<summary>health-services/resource-generator/src/main/java/org/egov/processor/util/FilestoreUtil.java (2)</summary><blockquote>

<details>
<summary>health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java (1)</summary>

* `Slf4j` (42-898)

</details>
<details>
<summary>health-services/resource-generator/src/main/java/org/egov/processor/util/ParsingUtil.java (1)</summary>

* `Slf4j` (32-481)

</details>

</blockquote></details>
<details>
<summary>health-services/resource-generator/src/main/java/org/egov/processor/service/DraftService.java (1)</summary><blockquote>

<details>
<summary>health-services/resource-generator/src/main/java/org/egov/processor/service/ResourceEstimationService.java (1)</summary>

* `Service` (20-120)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>🔇 Additional comments (30)</summary><blockquote>

<details>
<summary>health-services/resource-generator/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java (1)</summary>

`9-9`: **Import statements added for necessary functionality**

The added imports support the new methods: `ObjectUtils` for null-safe checking and constants for file template identifiers which improve code readability by eliminating magic strings.



Also applies to: 17-18

</details>
<details>
<summary>health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java (2)</summary>

`9-11`: **LGTM: Appropriate imports added.**

The imports for `CustomException` and `ObjectUtils` are correctly added, which are necessary for exception handling and object validation in the new `processDraftOutputFile` method.

---

`281-282`: **LGTM: Correct exception handling pattern.**

Proper validation is used to check if the README sheet name is empty, and a custom exception is thrown with appropriate error codes and messages.

</details>
<details>
<summary>health-services/resource-generator/src/main/java/org/egov/processor/web/models/DraftRequest.java (1)</summary>

`8-17`: **LGTM! Model class follows conventions and best practices.**

The `DraftRequest` class follows the standard conventions with appropriate annotations for validation and JSON mapping. The use of Lombok's `@Data` reduces boilerplate code.

</details>
<details>
<summary>health-services/resource-generator/src/main/java/org/egov/processor/service/ResourceEstimationService.java (1)</summary>

`56-56`: **Good refactoring - method extraction to utility class.**

The change simplifies the code by eliminating an intermediate method and directly using the utility class. This improves maintainability by centralizing the campaign search logic.

</details>
<details>
<summary>health-services/resource-generator/src/main/java/org/egov/processor/web/controllers/FileController.java (1)</summary>

`15-20`: **Minor import organization changes.**

The changes are just reorganization of import statements and don't affect functionality.

</details>
<details>
<summary>health-services/resource-generator/src/main/java/org/egov/processor/web/models/DraftDetails.java (1)</summary>

`1-20`: **Well-structured model class with proper validations.**

The model class is implemented correctly with appropriate field validations and JSON property mappings. The use of Lombok's `@Data` annotation helps reduce boilerplate code.

</details>
<details>
<summary>health-services/resource-generator/src/main/java/org/egov/processor/config/ErrorConstants.java (1)</summary>

`69-70`: **Error constants added for workbook operations.**

These error constants follow the existing pattern and provide clear error messages for workbook reading failures, which will help with error reporting and handling when processing Excel files.

</details>
<details>
<summary>health-services/resource-generator/src/main/java/org/egov/processor/util/FilestoreUtil.java (3)</summary>

`3-6`: **Imports reorganization looks good.**

These changes simply reorder or consolidate the JSON processing & logging imports. No concerns identified.

---

`20-24`: **No functional issues in these import statements.**

The addition of `java.io.File`, `java.io.IOException`, `java.nio.file.Files`, `java.util.Arrays`, and `java.util.List` is appropriate for file handling and collections usage in this utility class.

---

`26-28`: **Static imports consolidation is fine.**

Ensuring all relevant constants are pulled from `ServiceConstants` and `ErrorConstants` helps keep the code consistent. No issues noted.

</details>
<details>
<summary>health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java (2)</summary>

`42-43`: **Added draft file identifiers.**

The newly introduced constants for draft states (`DraftInprogress`, `DraftComplete`) streamline identifying file templates. This improves clarity for different file statuses.

---

`132-132`: **New DRAFT_STATUS constant.**

Defining `"DRAFT"` as a constant fosters consistency in referencing draft statuses across the codebase.

</details>
<details>
<summary>health-services/resource-generator/src/main/java/org/egov/processor/service/DraftService.java (8)</summary>

`1-9`: **New DraftService class introduced.**

Marking this class with `@Service` and `@Async` aligns with Spring’s approach for asynchronous execution. The constructor-based dependency injection is clear and maintainable.

---

`20-37`: **Sufficient utility field declarations.**

All utilities (e.g., `PlanConfigurationUtil`, `ExcelParser`, etc.) are injected as private fields. This approach is clean and ensures proper separation of concerns for different tasks (file parsing, campaign integration, etc.).

---

`39-49`: **Constructor ensures required dependencies are initialized.**

The constructor comprehensively initializes all utilities. This is a straightforward and effective approach to manage service dependencies.

---

`51-65`: **Potential out-of-bounds risk with `planConfigurationList.get(0)`.**

If `planConfigurationList` is empty, calling `get(0)` triggers an `IndexOutOfBoundsException`. Consider handling the case when no plan configurations are found.  

Do you want to add a null or empty list check to avoid potential runtime errors?

---

`70-77`: **Enrichment approach is well-structured.**

Enriching the resource mapping after retrieving locale and campaign data is a good practice for maintaining clarity in the code flow. No issues identified.

---

`85-88`: **Conditional sheet processing is sensible.**

Filtering sheets with `isSheetAllowedToProcess()` avoids unnecessary processing. This is a neat approach to controlling which sheets are handled.

---

`90-99`: **Output handling is properly sequenced.**

The file is localized, converted to XLS, uploaded, and then referenced in the plan configuration request. This sequence is logical.

---

`102-109`: **Filtering for population template.**

This helper method effectively retrieves a matching filestore ID by checking `templateIdentifier`. Consider alerting or erroring if no matching file is found, to avoid potential null usage downstream.  

Would you like to raise an exception or warning if no population file is found?

</details>
<details>
<summary>health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java (9)</summary>

`211-211`: **Method call updated to match the new signature.**

The method call now correctly excludes the PlanConfigurationRequest parameter to align with the method signature change on line 456.

---

`384-387`: **Well-structured method signature refactoring.**

Good changes to the `processRows` method:
1. Visibility changed from private to protected, enabling subclass extension
2. Added a `skipFixedPost` boolean parameter to control fixed post processing behavior

This increases the method's flexibility and reusability while maintaining its core functionality.

---

`389-394`: **Good implementation of conditional logic for fixed post details.**

The code now conditionally fetches fixed post details based on the `skipFixedPost` flag, providing an empty map when skipping. This optimization can improve performance when fixed post details aren't needed.

---

`438-439`: **Appropriate visibility change for reusability.**

Changing `getBoundaryCodeList` from private to package-private (default) visibility allows other classes in the same package to reuse this method, which is good for maintainability.

---

`456-456`: **Well-executed method signature simplification.**

Good refactoring to:
1. Change visibility from private to public, allowing access from other classes
2. Remove the unnecessary PlanConfigurationRequest parameter, simplifying the method signature

This enhances the method's reusability across the codebase.

---

`475-476`: **Method signature updated to support new functionality.**

The method signature has been updated to include the new `skipFixedPost` parameter, ensuring consistent parameter passing through the call chain.

---

`511-519`: **Added support for draft mode and conditional processing.**

Two important improvements:
1. Mixed strategy processing is now conditional based on the `skipFixedPost` flag
2. Plan creation only happens when the configuration status is not `DRAFT_STATUS`

This enables draft mode functionality where calculations are performed but plans aren't created until finalized, supporting the new draft API feature.

---

`568-568`: **Appropriate visibility change for reusability.**

Changing `uploadConvertedFile` from private to package-private visibility enables other classes in the same package to access this utility method, improving code reuse.

---

`870-896`: **Well-implemented utility method for workbook retrieval.**

Excellent addition of the `getWorkbookFromFilestoreId` method which:
1. Encapsulates the logic to retrieve and create a workbook from filestore
2. Provides proper error handling for file retrieval and workbook creation
3. Uses appropriate logging and exception handling

This method will support the new draft processing feature by providing a reusable way to access workbooks.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-03T05:18:35Z
user: login: Priyanka-eGov
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-03T05:19:55Z
user: login: Priyanka-eGov
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-03T05:21:26Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-03T05:22:40Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-03T05:23:41Z
user: login: Priyanka-eGov
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-03T05:41:00Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-03T05:41:25Z
user: login: Priyanka-eGov
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-03T05:43:56Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-03T05:44:19Z
user: login: Priyanka-eGov
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-03T05:56:02Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-03T05:56:52Z
user: login: Priyanka-eGov
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-03T05:58:53Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-03T05:59:40Z
user: login: Priyanka-eGov
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-03T06:05:47Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-03T06:09:52Z
user: login: Priyanka-eGov
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-03T06:23:26Z
user: login: coderabbitai[bot]
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-03T06:23:36Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-03T06:26:16Z

Review comments:
diff_hunk: @@ -63,4 +66,63 @@ public List<PlanConfiguration> search(PlanConfigurationSearchRequest planConfigu
     public void orderPlanConfigurationOperations(PlanConfigurationRequest planConfigurationRequest) {
         planConfigurationRequest.getPlanConfiguration().getOperations().sort(Comparator.comparingInt(Operation::getExecutionOrder));
     }
+
+    /**
+     * Builds a PlanConfigurationSearchRequest using information from the DraftRequest,
+     * including the plan configuration ID, tenant ID, and request info.
+     *
+     * @param draftRequest the DraftRequest containing search details
+     * @return a PlanConfigurationSearchRequest with the search criteria and request info
+     */
+    public PlanConfigurationSearchRequest buildPlanConfigurationSearchRequest(DraftRequest draftRequest) {
+        PlanConfigurationSearchCriteria searchCriteria = PlanConfigurationSearchCriteria.builder()
+                .id(draftRequest.getDraftDetails().getPlanConfigurationId())
+                .tenantId(draftRequest.getDraftDetails().getTenantId())
+                .build();
+
+        return PlanConfigurationSearchRequest.builder()
+                .requestInfo(draftRequest.getRequestInfo())
+                .planConfigurationSearchCriteria(searchCriteria)
+                .build();
+    }
path: health-services/resource-generator/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Method looks good but could benefit from null validation**

The `buildPlanConfigurationSearchRequest` method effectively constructs a search request using the builder pattern. However, there's no validation for null `draftRequest` or its components, which could lead to NullPointerExceptions if invalid input is provided.


```diff
public PlanConfigurationSearchRequest buildPlanConfigurationSearchRequest(DraftRequest draftRequest) {
+    if (draftRequest == null || draftRequest.getDraftDetails() == null) {
+        throw new IllegalArgumentException("DraftRequest or DraftDetails cannot be null");
+    }
+    
    PlanConfigurationSearchCriteria searchCriteria = PlanConfigurationSearchCriteria.builder()
            .id(draftRequest.getDraftDetails().getPlanConfigurationId())
            .tenantId(draftRequest.getDraftDetails().getTenantId())
            .build();

    return PlanConfigurationSearchRequest.builder()
            .requestInfo(draftRequest.getRequestInfo())
            .planConfigurationSearchCriteria(searchCriteria)
            .build();
}
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    /**
     * Builds a PlanConfigurationSearchRequest using information from the DraftRequest,
     * including the plan configuration ID, tenant ID, and request info.
     *
     * @param draftRequest the DraftRequest containing search details
     * @return a PlanConfigurationSearchRequest with the search criteria and request info
     */
    public PlanConfigurationSearchRequest buildPlanConfigurationSearchRequest(DraftRequest draftRequest) {
        if (draftRequest == null || draftRequest.getDraftDetails() == null) {
            throw new IllegalArgumentException("DraftRequest or DraftDetails cannot be null");
        }
    
        PlanConfigurationSearchCriteria searchCriteria = PlanConfigurationSearchCriteria.builder()
                .id(draftRequest.getDraftDetails().getPlanConfigurationId())
                .tenantId(draftRequest.getDraftDetails().getTenantId())
                .build();

        return PlanConfigurationSearchRequest.builder()
                .requestInfo(draftRequest.getRequestInfo())
                .planConfigurationSearchCriteria(searchCriteria)
                .build();
    }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-04-03T05:18:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -63,4 +66,63 @@
     public void orderPlanConfigurationOperations(PlanConfigurationRequest planConfigurationRequest) {
         planConfigurationRequest.getPlanConfiguration().getOperations().sort(Comparator.comparingInt(Operation::getExecutionOrder));
     }
+
+    /**
+     * Builds a PlanConfigurationSearchRequest using information from the DraftRequest,
+     * including the plan configuration ID, tenant ID, and request info.
+     *
+     * @param draftRequest the DraftRequest containing search details
+     * @return a PlanConfigurationSearchRequest with the search criteria and request info
+     */
+    public PlanConfigurationSearchRequest buildPlanConfigurationSearchRequest(DraftRequest draftRequest) {
+        PlanConfigurationSearchCriteria searchCriteria = PlanConfigurationSearchCriteria.builder()
+                .id(draftRequest.getDraftDetails().getPlanConfigurationId())
+                .tenantId(draftRequest.getDraftDetails().getTenantId())
+                .build();
+
+        return PlanConfigurationSearchRequest.builder()
+                .requestInfo(draftRequest.getRequestInfo())
+                .planConfigurationSearchCriteria(searchCriteria)
+                .build();
+    }
+
+    /**
+     * Sets the filestore ID for the file with template identifier "ESTIMATIONS_IN_PROGRESS".
+     * If the file exists, the filestore ID is updated. If the file does not exist, a new file is added
+     * with the specified filestore ID and input file type.
+     *
+     * @param planConfigurationRequest the plan configuration request containing the list of files
+     * @param fileStoreId the filestore ID to set or add
+     * @param inputFileType the input file type for the new file if added
+     */
+    public void setOrAddFileForDraft(PlanConfigurationRequest planConfigurationRequest, String fileStoreId,
+                                                     File.InputFileTypeEnum inputFileType) {
+        List<File> files = planConfigurationRequest.getPlanConfiguration().getFiles();
+
+        // Check if file with the specified templateIdentifier exists
+        File existingFile = files.stream()
+                .filter(file -> FILE_TEMPLATE_IDENTIFIER_DRAFT_INPROGRESS.equals(file.getTemplateIdentifier()))
+                .findFirst()
+                .orElse(null);
+
+        if (!ObjectUtils.isEmpty(existingFile)) {
+            // If the file exists, update the filestoreId and change template identifier to Draft Complete
+            existingFile.setFilestoreId(fileStoreId);
+            existingFile.setTemplateIdentifier(FILE_TEMPLATE_IDENTIFIER_DRAFT_COMPLETE);
+        } else {
+            // If the file doesn't exist, add a new file
+            File estimationFile = File.builder()
+                    .filestoreId(fileStoreId)
+                    .inputFileType(inputFileType)
+                    .templateIdentifier(FILE_TEMPLATE_IDENTIFIER_DRAFT_COMPLETE)
+                    .active(true)
+                    .build();
+            files.add(estimationFile);
+        }
+
+        // Set workflow to null as in the original methods
+        planConfigurationRequest.getPlanConfiguration().setWorkflow(null);
+    }
path: health-services/resource-generator/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Well-structured file management method with minor improvement opportunities**

The `setOrAddFileForDraft` method effectively handles the file management logic with good use of streams and builders. The code includes helpful comments explaining the process.


Consider these improvements:

1. Add validation for the `fileStoreId` parameter
2. Provide more context on why setting workflow to null is necessary
3. For performance in high-frequency scenarios, consider using a traditional loop instead of streams

```diff
public void setOrAddFileForDraft(PlanConfigurationRequest planConfigurationRequest, String fileStoreId,
                                             File.InputFileTypeEnum inputFileType) {
+    if (planConfigurationRequest == null || fileStoreId == null || fileStoreId.isEmpty()) {
+        throw new IllegalArgumentException("PlanConfigurationRequest and fileStoreId cannot be null or empty");
+    }
+    
    List<File> files = planConfigurationRequest.getPlanConfiguration().getFiles();

    // Check if file with the specified templateIdentifier exists
    File existingFile = files.stream()
            .filter(file -> FILE_TEMPLATE_IDENTIFIER_DRAFT_INPROGRESS.equals(file.getTemplateIdentifier()))
            .findFirst()
            .orElse(null);

    if (!ObjectUtils.isEmpty(existingFile)) {
        // If the file exists, update the filestoreId and change template identifier to Draft Complete
        existingFile.setFilestoreId(fileStoreId);
        existingFile.setTemplateIdentifier(FILE_TEMPLATE_IDENTIFIER_DRAFT_COMPLETE);
    } else {
        // If the file doesn't exist, add a new file
        File estimationFile = File.builder()
                .filestoreId(fileStoreId)
                .inputFileType(inputFileType)
                .templateIdentifier(FILE_TEMPLATE_IDENTIFIER_DRAFT_COMPLETE)
                .active(true)
                .build();
        files.add(estimationFile);
    }

-    // Set workflow to null as in the original methods
+    // Set workflow to null to ensure plan configuration is processed as a new entity without workflow state
    planConfigurationRequest.getPlanConfiguration().setWorkflow(null);
}
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    /**
     * Sets the filestore ID for the file with template identifier "ESTIMATIONS_IN_PROGRESS".
     * If the file exists, the filestore ID is updated. If the file does not exist, a new file is added
     * with the specified filestore ID and input file type.
     *
     * @param planConfigurationRequest the plan configuration request containing the list of files
     * @param fileStoreId the filestore ID to set or add
     * @param inputFileType the input file type for the new file if added
     */
    public void setOrAddFileForDraft(PlanConfigurationRequest planConfigurationRequest, String fileStoreId,
                                                     File.InputFileTypeEnum inputFileType) {
+    if (planConfigurationRequest == null || fileStoreId == null || fileStoreId.isEmpty()) {
+        throw new IllegalArgumentException("PlanConfigurationRequest and fileStoreId cannot be null or empty");
+    }
+    
        List<File> files = planConfigurationRequest.getPlanConfiguration().getFiles();
    
        // Check if file with the specified templateIdentifier exists
        File existingFile = files.stream()
                .filter(file -> FILE_TEMPLATE_IDENTIFIER_DRAFT_INPROGRESS.equals(file.getTemplateIdentifier()))
                .findFirst()
                .orElse(null);
    
        if (!ObjectUtils.isEmpty(existingFile)) {
            // If the file exists, update the filestoreId and change template identifier to Draft Complete
            existingFile.setFilestoreId(fileStoreId);
            existingFile.setTemplateIdentifier(FILE_TEMPLATE_IDENTIFIER_DRAFT_COMPLETE);
        } else {
            // If the file doesn't exist, add a new file
            File estimationFile = File.builder()
                    .filestoreId(fileStoreId)
                    .inputFileType(inputFileType)
                    .templateIdentifier(FILE_TEMPLATE_IDENTIFIER_DRAFT_COMPLETE)
                    .active(true)
                    .build();
            files.add(estimationFile);
        }
    
-    // Set workflow to null as in the original methods
+    // Set workflow to null to ensure plan configuration is processed as a new entity without workflow state
        planConfigurationRequest.getPlanConfiguration().setWorkflow(null);
    }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-04-03T05:18:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -75,6 +75,35 @@ public void processOutputFile(Workbook workbook, PlanConfigurationRequest reques
 
     }
 
+    /**
+     * Processes an output Excel workbook by removing unnecessary sheets, localizing header columns
+     * for each boundary code. The configuration for processing
+     * is based on the provided PlanConfigurationRequest.
+     *
+     * @param workbook   the Excel workbook to process
+     * @param request    the PlanConfigurationRequest containing processing configuration
+     */
+    public void processDraftOutputFile(Workbook workbook, PlanConfigurationRequest request) {
+        LocaleResponse localeResponse = localeUtil.searchLocale(request);
+        Map<String, Object> mdmsDataForCommonConstants = mdmsUtil.fetchMdmsDataForCommonConstants(
+                request.getRequestInfo(),
+                request.getPlanConfiguration().getTenantId());
+
+        // 1. removing readme sheet
+        for (int i = workbook.getNumberOfSheets() - 1; i >= 0; i--) {
+            Sheet sheet = workbook.getSheetAt(i);
+            if (!isSheetAllowedToProcess(sheet.getSheetName(), localeResponse, mdmsDataForCommonConstants)) {
+                workbook.removeSheetAt(i);
+            }
+        }
+
+        // 2. Stylize and localize output column headers
+        for(Sheet sheet: workbook) {
+            processSheetForHeaderLocalization(sheet, localeResponse);
+        }
+
+    }
path: health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Consider refactoring duplicated code between `processOutputFile` and `processDraftOutputFile`.**

The new `processDraftOutputFile` method duplicates most of the logic from the existing `processOutputFile` method, but omits the facility information addition step. This duplication could lead to maintenance issues if one method is updated but the other isn't.


Consider refactoring to extract the common code into a private helper method:

```diff
-    public void processOutputFile(Workbook workbook, PlanConfigurationRequest request, String filestoreId) {
-        LocaleResponse localeResponse = localeUtil.searchLocale(request);
-        Map<String, Object> mdmsDataForCommonConstants = mdmsUtil.fetchMdmsDataForCommonConstants(
-                request.getRequestInfo(),
-                request.getPlanConfiguration().getTenantId());
-
-        // 1. removing readme sheet
-        for (int i = workbook.getNumberOfSheets() - 1; i >= 0; i--) {
-            Sheet sheet = workbook.getSheetAt(i);
-            if (!isSheetAllowedToProcess(sheet.getSheetName(), localeResponse, mdmsDataForCommonConstants)) {
-                workbook.removeSheetAt(i);
-            }
-        }
-
-        // 2. Stylize and localize output column headers
-        for(Sheet sheet: workbook) {
-            processSheetForHeaderLocalization(sheet, localeResponse);
-        }
+    public void processOutputFile(Workbook workbook, PlanConfigurationRequest request, String filestoreId) {
+        LocaleResponse localeResponse = preprocessWorkbook(workbook, request);
+        
         // 3. Adding facility information for each boundary code
         for(Sheet sheet: workbook) {
             addAssignedFacility(sheet, request, filestoreId);
         }
     }

-    public void processDraftOutputFile(Workbook workbook, PlanConfigurationRequest request) {
-        LocaleResponse localeResponse = localeUtil.searchLocale(request);
-        Map<String, Object> mdmsDataForCommonConstants = mdmsUtil.fetchMdmsDataForCommonConstants(
-                request.getRequestInfo(),
-                request.getPlanConfiguration().getTenantId());
-
-        // 1. removing readme sheet
-        for (int i = workbook.getNumberOfSheets() - 1; i >= 0; i--) {
-            Sheet sheet = workbook.getSheetAt(i);
-            if (!isSheetAllowedToProcess(sheet.getSheetName(), localeResponse, mdmsDataForCommonConstants)) {
-                workbook.removeSheetAt(i);
-            }
-        }
-
-        // 2. Stylize and localize output column headers
-        for(Sheet sheet: workbook) {
-            processSheetForHeaderLocalization(sheet, localeResponse);
-        }
+    public void processDraftOutputFile(Workbook workbook, PlanConfigurationRequest request) {
+        preprocessWorkbook(workbook, request);
     }
+    
+    /**
+     * Preprocesses an output Excel workbook by removing unnecessary sheets and localizing header columns.
+     * 
+     * @param workbook the Excel workbook to process
+     * @param request the PlanConfigurationRequest containing processing configuration
+     * @return the LocaleResponse for further processing if needed
+     */
+    private LocaleResponse preprocessWorkbook(Workbook workbook, PlanConfigurationRequest request) {
+        LocaleResponse localeResponse = localeUtil.searchLocale(request);
+        Map<String, Object> mdmsDataForCommonConstants = mdmsUtil.fetchMdmsDataForCommonConstants(
+                request.getRequestInfo(),
+                request.getPlanConfiguration().getTenantId());
+
+        // 1. removing readme sheet
+        for (int i = workbook.getNumberOfSheets() - 1; i >= 0; i--) {
+            Sheet sheet = workbook.getSheetAt(i);
+            if (!isSheetAllowedToProcess(sheet.getSheetName(), localeResponse, mdmsDataForCommonConstants)) {
+                workbook.removeSheetAt(i);
+            }
+        }
+
+        // 2. Stylize and localize output column headers
+        for(Sheet sheet: workbook) {
+            processSheetForHeaderLocalization(sheet, localeResponse);
+        }
+        
+        return localeResponse;
+    }
```

This refactoring would:
1. Eliminate code duplication
2. Make the intent of each method clearer
3. Simplify maintenance by centralizing the common preprocessing logic


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    public void processOutputFile(Workbook workbook, PlanConfigurationRequest request, String filestoreId) {
-        LocaleResponse localeResponse = localeUtil.searchLocale(request);
-        Map<String, Object> mdmsDataForCommonConstants = mdmsUtil.fetchMdmsDataForCommonConstants(
-                request.getRequestInfo(),
-                request.getPlanConfiguration().getTenantId());
-
-        // 1. removing readme sheet
-        for (int i = workbook.getNumberOfSheets() - 1; i >= 0; i--) {
-            Sheet sheet = workbook.getSheetAt(i);
-            if (!isSheetAllowedToProcess(sheet.getSheetName(), localeResponse, mdmsDataForCommonConstants)) {
-                workbook.removeSheetAt(i);
-            }
-        }
-
-        // 2. Stylize and localize output column headers
-        for(Sheet sheet: workbook) {
-            processSheetForHeaderLocalization(sheet, localeResponse);
-        }
+        LocaleResponse localeResponse = preprocessWorkbook(workbook, request);
 
         // 3. Adding facility information for each boundary code
         for(Sheet sheet: workbook) {
             addAssignedFacility(sheet, request, filestoreId);
         }
     }
 
-    public void processDraftOutputFile(Workbook workbook, PlanConfigurationRequest request) {
-        LocaleResponse localeResponse = localeUtil.searchLocale(request);
-        Map<String, Object> mdmsDataForCommonConstants = mdmsUtil.fetchMdmsDataForCommonConstants(
-                request.getRequestInfo(),
-                request.getPlanConfiguration().getTenantId());
-
-        // 1. removing readme sheet
-        for (int i = workbook.getNumberOfSheets() - 1; i >= 0; i--) {
-            Sheet sheet = workbook.getSheetAt(i);
-            if (!isSheetAllowedToProcess(sheet.getSheetName(), localeResponse, mdmsDataForCommonConstants)) {
-                workbook.removeSheetAt(i);
-            }
-        }
-
-        // 2. Stylize and localize output column headers
-        for(Sheet sheet: workbook) {
-            processSheetForHeaderLocalization(sheet, localeResponse);
-        }
+    public void processDraftOutputFile(Workbook workbook, PlanConfigurationRequest request) {
+        preprocessWorkbook(workbook, request);
     }
 
+    /**
+     * Preprocesses an output Excel workbook by removing unnecessary sheets and localizing header columns.
+     * 
+     * @param workbook the Excel workbook to process
+     * @param request the PlanConfigurationRequest containing processing configuration
+     * @return the LocaleResponse for further processing if needed
+     */
+    private LocaleResponse preprocessWorkbook(Workbook workbook, PlanConfigurationRequest request) {
+        LocaleResponse localeResponse = localeUtil.searchLocale(request);
+        Map<String, Object> mdmsDataForCommonConstants = mdmsUtil.fetchMdmsDataForCommonConstants(
+                request.getRequestInfo(),
+                request.getPlanConfiguration().getTenantId());
+
+        // 1. removing readme sheet
+        for (int i = workbook.getNumberOfSheets() - 1; i >= 0; i--) {
+            Sheet sheet = workbook.getSheetAt(i);
+            if (!isSheetAllowedToProcess(sheet.getSheetName(), localeResponse, mdmsDataForCommonConstants)) {
+                workbook.removeSheetAt(i);
+            }
+        }
+
+        // 2. Stylize and localize output column headers
+        for(Sheet sheet: workbook) {
+            processSheetForHeaderLocalization(sheet, localeResponse);
+        }
+        
+        return localeResponse;
+    }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-04-03T05:18:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -31,6 +31,20 @@ public CampaignIntegrationUtil(ServiceRequestRepository serviceRequestRepository
 		this.mapper = mapper;
 	}
 
+	/**
+	 * Performs a campaign search based on the provided plan configuration request.
+	 * This method builds a campaign search request using the integration utility,
+	 * fetches the search result from the service request repository, and returns it.
+	 *
+	 * @param planConfigurationRequest The request object containing configuration details for the campaign search.
+	 * @return The response object containing the result of the campaign search.
+	 */
+    public Object performCampaignSearch(PlanConfigurationRequest planConfigurationRequest) {
+		CampaignSearchRequest campaignRequest = buildCampaignRequestForSearch(planConfigurationRequest);
+		return serviceRequestRepository.fetchResult(new StringBuilder(config.getProjectFactoryHostEndPoint()+config.getCampaignIntegrationSearchEndPoint()),
+				campaignRequest);
+	}
path: health-services/resource-generator/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Consider using a more specific return type.**

The method returns `Object` which is very generic. This may require type casting at the call site and could lead to runtime errors.


Consider specifying a more concrete return type (such as `CampaignResponse`) or adding a generic type parameter:

```diff
-public Object performCampaignSearch(PlanConfigurationRequest planConfigurationRequest) {
+public CampaignResponse performCampaignSearch(PlanConfigurationRequest planConfigurationRequest) {
    CampaignSearchRequest campaignRequest = buildCampaignRequestForSearch(planConfigurationRequest);
-    return serviceRequestRepository.fetchResult(new StringBuilder(config.getProjectFactoryHostEndPoint()+config.getCampaignIntegrationSearchEndPoint()),
+    Object result = serviceRequestRepository.fetchResult(new StringBuilder(config.getProjectFactoryHostEndPoint()+config.getCampaignIntegrationSearchEndPoint()),
            campaignRequest);
+    return parseCampaignResponse(result);
}
```


> Committable suggestion skipped: line range outside the PR's diff.

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-04-03T05:18:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -31,6 +31,20 @@
 		this.mapper = mapper;
 	}
 
+	/**
+	 * Performs a campaign search based on the provided plan configuration request.
+	 * This method builds a campaign search request using the integration utility,
+	 * fetches the search result from the service request repository, and returns it.
+	 *
+	 * @param planConfigurationRequest The request object containing configuration details for the campaign search.
+	 * @return The response object containing the result of the campaign search.
+	 */
+    public Object performCampaignSearch(PlanConfigurationRequest planConfigurationRequest) {
+		CampaignSearchRequest campaignRequest = buildCampaignRequestForSearch(planConfigurationRequest);
+		return serviceRequestRepository.fetchResult(new StringBuilder(config.getProjectFactoryHostEndPoint()+config.getCampaignIntegrationSearchEndPoint()),
+				campaignRequest);
+	}
path: health-services/resource-generator/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Well-documented public method, but consider adding exception handling.**

The new `performCampaignSearch` method is nicely documented with detailed JavaDoc. However, unlike similar methods in this class (like `updateResourcesInProjectFactory` and `createProjectFactoryDataCall`), it lacks exception handling.


Consider adding exception handling to make this method consistent with others:

```diff
public Object performCampaignSearch(PlanConfigurationRequest planConfigurationRequest) {
+    try {
        CampaignSearchRequest campaignRequest = buildCampaignRequestForSearch(planConfigurationRequest);
        return serviceRequestRepository.fetchResult(new StringBuilder(config.getProjectFactoryHostEndPoint()+config.getCampaignIntegrationSearchEndPoint()),
                campaignRequest);
+    } catch (Exception e) {
+        log.error("Error while fetching campaign details: " + planConfigurationRequest.getPlanConfiguration().getId(), e);
+        throw new CustomException("ERROR_FETCHING_CAMPAIGN_DETAILS", e.toString());
+    }
}
```

Adding logging would also help with debugging.


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
	/**
	 * Performs a campaign search based on the provided plan configuration request.
	 * This method builds a campaign search request using the integration utility,
	 * fetches the search result from the service request repository, and returns it.
	 *
	 * @param planConfigurationRequest The request object containing configuration details for the campaign search.
	 * @return The response object containing the result of the campaign search.
	 */
    public Object performCampaignSearch(PlanConfigurationRequest planConfigurationRequest) {
        try {
		    CampaignSearchRequest campaignRequest = buildCampaignRequestForSearch(planConfigurationRequest);
		    return serviceRequestRepository.fetchResult(
                new StringBuilder(config.getProjectFactoryHostEndPoint() + config.getCampaignIntegrationSearchEndPoint()),
                campaignRequest
            );
        } catch (Exception e) {
            log.error("Error while fetching campaign details: " + planConfigurationRequest.getPlanConfiguration().getId(), e);
            throw new CustomException("ERROR_FETCHING_CAMPAIGN_DETAILS", e.toString());
        }
    }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-04-03T05:18:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -6,10 +6,12 @@
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.Import;
+import org.springframework.scheduling.annotation.EnableAsync;
path: health-services/resource-generator/src/main/java/org/egov/processor/Main.java
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Appropriate addition of asynchronous execution support.**

The `@EnableAsync` annotation is correctly added to enable asynchronous processing within the application. This aligns with the implementation of asynchronous methods in the new DraftService.


Consider defining a custom thread pool configuration (like `TaskExecutor`) to control thread management instead of relying on Spring's default configuration, especially if you expect high load or long-running tasks.



Also applies to: 14-14

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-03T05:18:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,25 @@
+package org.egov.processor.web.controllers;
+
+import jakarta.validation.Valid;
+import org.egov.processor.service.DraftService;
+import org.egov.processor.web.models.DraftRequest;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+@Controller
+public class DraftController {
+
+    private DraftService draftService;
+
+    public DraftController(DraftService draftService) {
+        this.draftService = draftService;
+    }
+
+    @PostMapping("/draft")
+    public ResponseEntity<String> createDraftMicroplan(@RequestBody @Valid DraftRequest draftRequest) {
+        draftService.createDraftPlans(draftRequest);
+        return ResponseEntity.ok("Draft processing started successfully.");
+    }
path: health-services/resource-generator/src/main/java/org/egov/processor/web/controllers/DraftController.java
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Return HTTP 202 Accepted for asynchronous operations.**

Since the operation is processed asynchronously, returning HTTP 202 Accepted would be more appropriate than HTTP 200 OK, as it better communicates that the request has been accepted for processing but is not yet complete.


```diff
 @PostMapping("/draft")
 public ResponseEntity<String> createDraftMicroplan(@RequestBody @Valid DraftRequest draftRequest) {
     draftService.createDraftPlans(draftRequest);
-    return ResponseEntity.ok("Draft processing started successfully.");
+    return ResponseEntity.accepted().body("Draft processing started successfully.");
 }
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    @PostMapping("/draft")
    public ResponseEntity<String> createDraftMicroplan(@RequestBody @Valid DraftRequest draftRequest) {
        draftService.createDraftPlans(draftRequest);
        return ResponseEntity.accepted().body("Draft processing started successfully.");
    }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-04-03T05:18:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,25 @@
+package org.egov.processor.web.controllers;
+
+import jakarta.validation.Valid;
+import org.egov.processor.service.DraftService;
+import org.egov.processor.web.models.DraftRequest;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+@Controller
+public class DraftController {
+
+    private DraftService draftService;
+
+    public DraftController(DraftService draftService) {
+        this.draftService = draftService;
+    }
+
+    @PostMapping("/draft")
+    public ResponseEntity<String> createDraftMicroplan(@RequestBody @Valid DraftRequest draftRequest) {
+        draftService.createDraftPlans(draftRequest);
+        return ResponseEntity.ok("Draft processing started successfully.");
+    }
+}
path: health-services/resource-generator/src/main/java/org/egov/processor/web/controllers/DraftController.java
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Controller implemented with asynchronous processing, but lacks proper error handling.**

The controller is structured appropriately with constructor injection and proper request mapping. The endpoint initiates an asynchronous operation and returns immediately, which is good for long-running processes.


However, there are several improvements needed:

1. Error handling is missing. Consider adding try-catch blocks or `@ExceptionHandler` methods to handle potential exceptions.
2. The response format is inconsistent with REST API best practices. Consider returning a standardized response object.
3. The endpoint naming (`/draft`) doesn't follow REST conventions. Consider using plural nouns (e.g., `/drafts`).
4. API documentation (using Swagger/OpenAPI annotations) should be added for better API discoverability.


```diff
 @Controller
 public class DraftController {
 
     private DraftService draftService;
 
     public DraftController(DraftService draftService) {
         this.draftService = draftService;
     }
 
-    @PostMapping("/draft")
-    public ResponseEntity<String> createDraftMicroplan(@RequestBody @Valid DraftRequest draftRequest) {
-        draftService.createDraftPlans(draftRequest);
-        return ResponseEntity.ok("Draft processing started successfully.");
+    @PostMapping("/drafts")
+    public ResponseEntity<Map<String, String>> createDraftMicroplan(@RequestBody @Valid DraftRequest draftRequest) {
+        try {
+            draftService.createDraftPlans(draftRequest);
+            return ResponseEntity.accepted()
+                .body(Collections.singletonMap("message", "Draft processing started successfully."));
+        } catch (Exception e) {
+            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+                .body(Collections.singletonMap("error", "Failed to start draft processing: " + e.getMessage()));
+        }
     }
 }
```


> Committable suggestion skipped: line range outside the PR's diff.

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-04-03T05:18:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,112 @@
+package org.egov.processor.service;
+
+import org.apache.poi.ss.usermodel.Workbook;
+import org.egov.processor.util.*;
+import org.egov.processor.web.models.*;
+import org.egov.processor.web.models.campaignManager.CampaignResponse;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.egov.processor.config.ServiceConstants.FILE_TEMPLATE_IDENTIFIER_POPULATION;
+import static org.egov.processor.web.models.File.InputFileTypeEnum.EXCEL;
+
+@Service
+public class DraftService {
+
+    private PlanConfigurationUtil planConfigurationUtil;
+
+    private ExcelParser excelParser;
+
+    private ParsingUtil parsingUtil;
+
+    private PlanUtil planUtil;
+
+    private CampaignIntegrationUtil campaignIntegrationUtil;
+
+    private MdmsUtil mdmsUtil;
+
+    private LocaleUtil localeUtil;
+
+    private EnrichmentUtil enrichmentUtil;
+
+    private OutputEstimationGenerationUtil outputEstimationGenerationUtil;
+
+
+    public DraftService(PlanConfigurationUtil planConfigurationUtil, ExcelParser excelParser, ParsingUtil parsingUtil, PlanUtil planUtil, CampaignIntegrationUtil campaignIntegrationUtil, MdmsUtil mdmsUtil, LocaleUtil localeUtil, EnrichmentUtil enrichmentUtil, OutputEstimationGenerationUtil outputEstimationGenerationUtil) {
+        this.planConfigurationUtil = planConfigurationUtil;
+        this.excelParser = excelParser;
+        this.parsingUtil = parsingUtil;
+        this.planUtil = planUtil;
+        this.campaignIntegrationUtil = campaignIntegrationUtil;
+        this.mdmsUtil = mdmsUtil;
+        this.localeUtil = localeUtil;
+        this.enrichmentUtil = enrichmentUtil;
+        this.outputEstimationGenerationUtil = outputEstimationGenerationUtil;
+    }
+
+    @Async
+    public void createDraftPlans(DraftRequest draftRequest) {
+        // Retrieve Plan Configuration
+        List<PlanConfiguration> planConfigurationList = planConfigurationUtil.search(planConfigurationUtil.buildPlanConfigurationSearchRequest(draftRequest));
+        PlanConfigurationRequest request = PlanConfigurationRequest.builder()
+                .requestInfo(draftRequest.getRequestInfo())
+                .planConfiguration(planConfigurationList.get(0))
+                .build();
+
+        // Get filestoreId for population template
+        String fileStoreId = getFilestoreIdForPopulationTemplate(request.getPlanConfiguration());
+
+        // Retrieve data and perform actions
+        Workbook workbook = excelParser.getWorkbookFromFilestoreId(fileStoreId, request.getPlanConfiguration().getTenantId());
+        Object campaignSearchResponse = campaignIntegrationUtil.performCampaignSearch(request);
+        CampaignResponse campaign = campaignIntegrationUtil.parseCampaignResponse(campaignSearchResponse);
+        LocaleResponse localeResponse = localeUtil.searchLocale(request);
+        Object mdmsData = mdmsUtil.fetchMdmsData(request.getRequestInfo(), request.getPlanConfiguration().getTenantId());
+
path: health-services/resource-generator/src/main/java/org/egov/processor/service/DraftService.java
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Possible campaign array out-of-bounds.**

`campaign.getCampaign().get(0)` may cause an `IndexOutOfBoundsException` if the campaign list is empty. A defensive check here can prevent runtime errors.  

Consider verifying that `campaign.getCampaign()` is non-empty before accessing the first element.

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-04-03T05:18:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -63,4 +66,63 @@ public List<PlanConfiguration> search(PlanConfigurationSearchRequest planConfigu
     public void orderPlanConfigurationOperations(PlanConfigurationRequest planConfigurationRequest) {
         planConfigurationRequest.getPlanConfiguration().getOperations().sort(Comparator.comparingInt(Operation::getExecutionOrder));
     }
+
+    /**
+     * Builds a PlanConfigurationSearchRequest using information from the DraftRequest,
+     * including the plan configuration ID, tenant ID, and request info.
+     *
+     * @param draftRequest the DraftRequest containing search details
+     * @return a PlanConfigurationSearchRequest with the search criteria and request info
+     */
+    public PlanConfigurationSearchRequest buildPlanConfigurationSearchRequest(DraftRequest draftRequest) {
+        PlanConfigurationSearchCriteria searchCriteria = PlanConfigurationSearchCriteria.builder()
+                .id(draftRequest.getDraftDetails().getPlanConfigurationId())
+                .tenantId(draftRequest.getDraftDetails().getTenantId())
+                .build();
+
+        return PlanConfigurationSearchRequest.builder()
+                .requestInfo(draftRequest.getRequestInfo())
+                .planConfigurationSearchCriteria(searchCriteria)
+                .build();
+    }
path: health-services/resource-generator/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java
user: login: Priyanka-eGov
body: annotation present in model.
created_at: 2025-04-03T05:19:55Z
author_association: COLLABORATOR
diff_hunk: @@ -63,4 +66,63 @@
     public void orderPlanConfigurationOperations(PlanConfigurationRequest planConfigurationRequest) {
         planConfigurationRequest.getPlanConfiguration().getOperations().sort(Comparator.comparingInt(Operation::getExecutionOrder));
     }
+
+    /**
+     * Builds a PlanConfigurationSearchRequest using information from the DraftRequest,
+     * including the plan configuration ID, tenant ID, and request info.
+     *
+     * @param draftRequest the DraftRequest containing search details
+     * @return a PlanConfigurationSearchRequest with the search criteria and request info
+     */
+    public PlanConfigurationSearchRequest buildPlanConfigurationSearchRequest(DraftRequest draftRequest) {
+        PlanConfigurationSearchCriteria searchCriteria = PlanConfigurationSearchCriteria.builder()
+                .id(draftRequest.getDraftDetails().getPlanConfigurationId())
+                .tenantId(draftRequest.getDraftDetails().getTenantId())
+                .build();
+
+        return PlanConfigurationSearchRequest.builder()
+                .requestInfo(draftRequest.getRequestInfo())
+                .planConfigurationSearchCriteria(searchCriteria)
+                .build();
+    }
+
+    /**
+     * Sets the filestore ID for the file with template identifier "ESTIMATIONS_IN_PROGRESS".
+     * If the file exists, the filestore ID is updated. If the file does not exist, a new file is added
+     * with the specified filestore ID and input file type.
+     *
+     * @param planConfigurationRequest the plan configuration request containing the list of files
+     * @param fileStoreId the filestore ID to set or add
+     * @param inputFileType the input file type for the new file if added
+     */
+    public void setOrAddFileForDraft(PlanConfigurationRequest planConfigurationRequest, String fileStoreId,
+                                                     File.InputFileTypeEnum inputFileType) {
+        List<File> files = planConfigurationRequest.getPlanConfiguration().getFiles();
+
+        // Check if file with the specified templateIdentifier exists
+        File existingFile = files.stream()
+                .filter(file -> FILE_TEMPLATE_IDENTIFIER_DRAFT_INPROGRESS.equals(file.getTemplateIdentifier()))
+                .findFirst()
+                .orElse(null);
+
+        if (!ObjectUtils.isEmpty(existingFile)) {
+            // If the file exists, update the filestoreId and change template identifier to Draft Complete
+            existingFile.setFilestoreId(fileStoreId);
+            existingFile.setTemplateIdentifier(FILE_TEMPLATE_IDENTIFIER_DRAFT_COMPLETE);
+        } else {
+            // If the file doesn't exist, add a new file
+            File estimationFile = File.builder()
+                    .filestoreId(fileStoreId)
+                    .inputFileType(inputFileType)
+                    .templateIdentifier(FILE_TEMPLATE_IDENTIFIER_DRAFT_COMPLETE)
+                    .active(true)
+                    .build();
+            files.add(estimationFile);
+        }
+
+        // Set workflow to null as in the original methods
+        planConfigurationRequest.getPlanConfiguration().setWorkflow(null);
+    }
path: health-services/resource-generator/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java
user: login: Priyanka-eGov
body: done
created_at: 2025-04-03T05:21:26Z
author_association: COLLABORATOR
diff_hunk: @@ -63,4 +66,63 @@ public List<PlanConfiguration> search(PlanConfigurationSearchRequest planConfigu
     public void orderPlanConfigurationOperations(PlanConfigurationRequest planConfigurationRequest) {
         planConfigurationRequest.getPlanConfiguration().getOperations().sort(Comparator.comparingInt(Operation::getExecutionOrder));
     }
+
+    /**
+     * Builds a PlanConfigurationSearchRequest using information from the DraftRequest,
+     * including the plan configuration ID, tenant ID, and request info.
+     *
+     * @param draftRequest the DraftRequest containing search details
+     * @return a PlanConfigurationSearchRequest with the search criteria and request info
+     */
+    public PlanConfigurationSearchRequest buildPlanConfigurationSearchRequest(DraftRequest draftRequest) {
+        PlanConfigurationSearchCriteria searchCriteria = PlanConfigurationSearchCriteria.builder()
+                .id(draftRequest.getDraftDetails().getPlanConfigurationId())
+                .tenantId(draftRequest.getDraftDetails().getTenantId())
+                .build();
+
+        return PlanConfigurationSearchRequest.builder()
+                .requestInfo(draftRequest.getRequestInfo())
+                .planConfigurationSearchCriteria(searchCriteria)
+                .build();
+    }
path: health-services/resource-generator/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java
user: login: coderabbitai[bot]
body: <details>
<summary>🧩 Analysis chain</summary>

@Priyanka-eGov I understand - you're right. After checking the model classes, I can see that `DraftRequest` has `@Valid` annotations on both `requestInfo` and `draftDetails` fields, and `DraftDetails` has `@NotNull` and other validation annotations on its fields. These Bean Validation annotations already ensure that null validation happens automatically when the request is processed by the framework, making the explicit null checks in the method unnecessary.



---

🏁 Script executed:
```
#!/bin/bash
# Check the DraftRequest and DraftDetails model classes for validation annotations
echo "Checking DraftRequest.java:"
rg -p "@NotNull|@Valid|@Size|@Pattern" health-services/resource-generator/src/main/java/org/egov/processor/web/models/DraftRequest.java

echo -e "\nChecking DraftDetails.java:"
rg -p "@NotNull|@Valid|@Size|@Pattern" health-services/resource-generator/src/main/java/org/egov/processor/web/models/DraftDetails.java

echo -e "\nFull content of DraftRequest.java:"
cat health-services/resource-generator/src/main/java/org/egov/processor/web/models/DraftRequest.java

echo -e "\nFull content of DraftDetails.java:"
cat health-services/resource-generator/src/main/java/org/egov/processor/web/models/DraftDetails.java
```

Length of output: 1824

---



</details>

@Priyanka-eGov You're absolutely right. Looking at the model classes, I can see the validation annotations:

- `DraftRequest` has `@Valid` on both the `requestInfo` and `draftDetails` fields
- `DraftDetails` has `@NotNull` and `@Size` constraints on the `tenantId` field, and `@Valid` with `@Size` on the `planConfigurationId`

These Bean Validation annotations already provide validation at the framework level before the method is called, making the explicit null checks redundant. Thank you for pointing this out.

---

<details>
<summary>🧬 Code Definitions Used</summary>

```plaintext
### Relevant Snippets for `PlanConfigurationUtil.java`

#### 1. `health-services/plan-service/src/main/java/digit/util/MdmsUtil.java` (Lines 26-117)
```java
@Slf4j
@Component
public class MdmsUtil {
    // ... (constructor and other methods)

    public Object fetchMdmsData(ProjectRequest request, String tenantId) {
        // ... (method implementation)
    }

    public MdmsCriteriaReq getMDMSRequest(RequestInfo requestInfo, String tenantId, ProjectRequest request) {
        // ... (method implementation)
    }

    private ModuleDetail getMDMSModuleRequestData(ProjectRequest request) {
        // ... (method implementation)
    }

    // ... (other methods)
}
```

#### 2. `health-services/plan-service/src/main/java/digit/util/BoundaryUtil.java` (Lines 19-110)
```java
@Slf4j
@Component
public class BoundaryUtil {
    // ... (constructor and other methods)

    public BoundarySearchResponse fetchBoundaryData(RequestInfo requestInfo, String boundaryCode, String tenantId, String hierarchyType, Boolean includeParents, Boolean includeChildren) {
        // ... (method implementation)
    }

    private StringBuilder getBoundaryRelationshipSearchUri(Map<String, String> uriParameters, String boundaryCode, String tenantId, String hierarchyType, Boolean includeParents, Boolean includeChildren) {
        // ... (method implementation)
    }

    // ... (other methods)
}
```

#### 3. `health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmRecipientIdValidator.java` (Lines 33-107)
```java
@Component
@Order(value = 3)
@Slf4j
public class RmRecipientIdValidator implements Validator<ReferralBulkRequest, Referral> {
    // ... (constructor and methods)

    @Override
    public Map<Referral, List<Error>> validate(ReferralBulkRequest request) {
        // ... (method implementation)
    }

    // ... (other methods)
}
```

#### 4. `health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectBeneficiaryIdValidator.java` (Lines 33-111)
```java
@Component
@Order(value = 3)
@Slf4j
public class SeProjectBeneficiaryIdValidator implements Validator<SideEffectBulkRequest, SideEffect> {
    // ... (constructor and methods)

    @Override
    public Map<SideEffect, List<Error>> validate(SideEffectBulkRequest request) {
        // ... (method implementation)
    }

    // ... (other methods)
}
```

#### 5. `health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrProjectIdValidator.java` (Lines 33-131)
```java
@Component
@Order(value = 3)
@Slf4j
public class HfrProjectIdValidator implements Validator<HFReferralBulkRequest, HFReferral> {
    // ... (constructor and methods)

    @Override
    public Map<HFReferral, List<Error>> validate(HFReferralBulkRequest request) {
        // ... (method implementation)
    }

    // ... (other methods)
}
```

#### 6. `health-services/project/src/main/java/org/egov/project/validator/task/PtProductVariantIdValidator.java` (Lines 36-114)
```java
@Component
@Order(value = 8)
@Slf4j
public class PtProductVariantIdValidator implements Validator<TaskBulkRequest, Task> {
    // ... (constructor and methods)

    @Override
    public Map<Task, List<Error>> validate(TaskBulkRequest request) {
        // ... (method implementation)
    }

    // ... (other methods)
}
```

#### 7. `health-services/project/src/main/java/org/egov/project/validator/useraction/UaProjectIdValidator.java` (Lines 32-96)
```java
@Component
@Order(value = 6)
@Slf4j
public class UaProjectIdValidator implements Validator<UserActionBulkRequest, UserAction> {
    // ... (constructor and methods)

    @Override
    public Map<UserAction, List<Error>> validate(UserActionBulkRequest request) {
        // ... (method implementation)
    }

    // ... (other methods)
}
```

#### 8. `health-services/plan-service/src/main/java/digit/util/PlanEmployeeAssignmentUtil.java` (Lines 17-76)
```java
@Slf4j
@Component
public class PlanEmployeeAssignmentUtil {
    // ... (constructor and methods)

    public PlanEmployeeAssignmentResponse fetchPlanEmployeeAssignment(PlanEmployeeAssignmentSearchRequest planEmployeeAssignmentSearchRequest) {
        // ... (method implementation)
    }

    // ... (other methods)
}
```

#### 9. `health-services/plan-service/src/main/java/digit/util/PlanConfigurationUtil.java` (Lines 1-120)
```java
@Component
@Slf4j
public class PlanConfigurationUtil {
    // ... (constructor and methods)

    public List<PlanConfiguration> search(PlanConfigurationSearchRequest planConfigurationSearchRequest) {
        // ... (method implementation)
    }

    // ... (other methods)
}
```
```

### Relevant Code Snippets

#### 1. **PlanConfigurationUtil.java**
- **Method: `search`**
  - **Description**: Searches for plan configurations based on the given search request.
  - **Parameters**: 
    - `PlanConfigurationSearchRequest planConfigurationSearchRequest`: The request object containing search criteria.
  - **Return**: A list of `PlanConfiguration` objects that match the search criteria. If no matching configurations are found or an error occurs, an empty list is returned.
  - **Exceptions**: Catches general exceptions and logs an error message.
  - **Line Numbers**: 27-56

```java
/**
 * Searches for plan configurations based on the given search request.
 *
 * @param planConfigurationSearchRequest The request object containing search criteria.
 * @return A list of planConfiguration objects that match the search criteria.
 *         If no matching configurations are found or an error occurs, an empty list is returned.
 */
public List<PlanConfiguration> search(PlanConfigurationSearchRequest planConfigurationSearchRequest) {
    // Implementation...
}
```

#### 2. **ErrorConstants.java**
- **Constant: `ERROR_WHILE_FETCHING_FROM_PLAN_SERVICE`**
  - **Description**: Error message constant used when there is an error fetching plan configuration from the plan service.
  - **Line Numbers**: 5-71

```java
public static final String ERROR_WHILE_FETCHING_FROM_PLAN_SERVICE = "Exception occurred while fetching plan configuration from plan service ";
```

#### 3. **ServiceConstants.java**
- **Constant: `FILE_TEMPLATE_IDENTIFIER_DRAFT_COMPLETE`**
  - **Description**: Constant used to identify the draft complete file template.
  - **Line Numbers**: 7-121

```java
public static final String FILE_TEMPLATE_IDENTIFIER_DRAFT_COMPLETE = "DraftComplete";
```

#### 4. **ServiceConstants.java (from another file)**
- **Constant: `FILE_TEMPLATE_IDENTIFIER_DRAFT_INPROGRESS`**
  - **Description**: Constant used to identify the draft in-progress file template.
  - **Line Numbers**: 7-133

```java
public static final String FILE_TEMPLATE_IDENTIFIER_DRAFT_INPROGRESS = "DraftInprogress";
```

#### 5. **PlanConfigurationUtil.java**
- **Method: `buildPlanConfigurationSearchRequest`**
  - **Description**: Builds a `PlanConfigurationSearchRequest` using information from the `DraftRequest`.
  - **Parameters**: 
    - `DraftRequest draftRequest`: The draft request containing search details.
  - **Return**: A `PlanConfigurationSearchRequest` with the search criteria and request info.
  - **Line Numbers**: 58-69

```java
/**
 * Builds a PlanConfigurationSearchRequest using information from the DraftRequest,
 * including the plan configuration ID, tenant ID, and request info.
 *
 * @param draftRequest the DraftRequest containing search details
 * @return a PlanConfigurationSearchRequest with the search criteria and request info
 */
public PlanConfigurationSearchRequest buildPlanConfigurationSearchRequest(DraftRequest draftRequest) {
    // Implementation...
}
```

#### 6. **FilestoreUtil.java**
- **Method: `getFileByteArray`**
  - **Description**: Retrieves a file from the file store service based on the tenant ID and file store ID.
  - **Parameters**: 
    - `String tenantId`: The ID of the tenant.
    - `String fileStoreId`: The ID of the file in the file store.
  - **Return**: The file content as a byte array.
  - **Exceptions**: Catches exceptions and logs an error message.
  - **Line Numbers**: 30-206

```java
/**
 * Retrieves a file from the file store service based on the tenant ID and file store ID.
 *
 * @param tenantId   The ID of the tenant.
 * @param fileStoreId The ID of the file in the file store.
 * @return The file content as a byte array.
 */
public byte[] getFileByteArray(String tenantId, String fileStoreId) {
    // Implementation...
}
```

#### 7. **CensusUtil.java**
- **Method: `create`**
  - **Description**: Creates and pushes a `CensusRequest` based on the provided plan configuration request.
  - **Parameters**: 
    - `PlanConfigurationRequest planConfigurationRequest`: The plan configuration request with necessary details.
    - `JsonNode feature`: The JSON node containing feature data for the census.
    - `Map<String, String> mappedValues`: A map of property names to their values from the feature node.
    - `String heirarchyType`: The type of hierarchy to be used in the census.
  - **Exceptions**: Catches exceptions and logs an error message.
  - **Line Numbers**: 27-228

```java
/**
 * Creates and pushes a CensusRequest based on the provided plan configuration request.
 *
 * @param planConfigurationRequest The plan configuration request with the necessary details.
 * @param feature                  The JSON node containing feature data for the census.
 * @param mappedValues             A map of property names to their values from the feature node.
 * @param heirarchyType            The type of hierarchy to be used in the census.
 */
public void create(PlanConfigurationRequest planConfigurationRequest, JsonNode feature, Map<String, String> mappedValues, String heirarchyType) {
    // Implementation...
}
```

#### 8. **CensusEnrichment.java**
- **Method: `enrichCreate`**
  - **Description**: Enriches the `CensusRequest` for creating a new census record.
  - **Parameters**: 
    - `CensusRequest request`: The census request to be enriched.
  - **Exceptions**: Throws a `CustomException` if user information is missing.
  - **Line Numbers**: 23-219

```java
/**
 * Enriches the CensusRequest for creating a new census record.
 * Enriches the given census record with generated IDs for Census and PopulationByDemographics.
 * Validates user information, enriches audit details and effectiveFrom for create operation.
 *
 * @param request The CensusRequest to be enriched.
 * @throws CustomException if user information is missing in the request.
 */
public void enrichCreate(CensusRequest request) {
    // Implementation...
}
```

### Summary
The snippets provided above are relevant to the `PlanConfigurationUtil.java` file and the user comment regarding annotations present in the model. They include methods for searching plan configurations, building search requests, and handling file operations, which may involve annotations in the model classes.

### Relevant Code Snippets

#### From `health-services/resource-generator/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java`

1. **Method: `search`**
   - **Description**: Searches for plan configurations based on the given search request.
   - **Parameters**: 
     - `PlanConfigurationSearchRequest planConfigurationSearchRequest`: The request object containing search criteria.
   - **Return**: A list of `PlanConfiguration` objects that match the search criteria. If no matching configurations are found or an error occurs, an empty list is returned.
   - **Exceptions**: Logs an error if an exception occurs during fetching.
   ```java
   public List<PlanConfiguration> search(PlanConfigurationSearchRequest planConfigurationSearchRequest) {
       // Implementation...
   }
   ```

2. **Method: `buildPlanConfigurationSearchRequest`**
   - **Description**: Builds a `PlanConfigurationSearchRequest` using information from the `DraftRequest`, including the plan configuration ID, tenant ID, and request info.
   - **Parameters**: 
     - `DraftRequest draftRequest`: The DraftRequest containing search details.
   - **Return**: A `PlanConfigurationSearchRequest` with the search criteria and request info.
   ```java
   public PlanConfigurationSearchRequest buildPlanConfigurationSearchRequest(DraftRequest draftRequest) {
       // Implementation...
   }
   ```

3. **Method: `setOrAddFileForDraft`**
   - **Description**: Sets the filestore ID for the file with template identifier "ESTIMATIONS_IN_PROGRESS". If the file exists, the filestore ID is updated. If the file does not exist, a new file is added with the specified filestore ID and input file type.
   - **Parameters**: 
     - `PlanConfigurationRequest planConfigurationRequest`: The plan configuration request containing the list of files.
     - `String fileStoreId`: The filestore ID to set or add.
     - `File.InputFileTypeEnum inputFileType`: The input file type for the new file if added.
   ```java
   public void setOrAddFileForDraft(PlanConfigurationRequest planConfigurationRequest, String fileStoreId, File.InputFileTypeEnum inputFileType) {
       // Implementation...
   }
   ```

#### From `health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java`

1. **Method: `processOutputFile`**
   - **Description**: Processes an output Excel workbook by removing unnecessary sheets, localizing header columns, and adding facility information for each boundary code.
   - **Parameters**: 
     - `Workbook workbook`: The Excel workbook to process.
     - `PlanConfigurationRequest request`: The PlanConfigurationRequest containing processing configuration.
     - `String filestoreId`: The identifier of the file store for additional processing requirements.
   ```java
   public void processOutputFile(Workbook workbook, PlanConfigurationRequest request, String filestoreId) {
       // Implementation...
   }
   ```

#### From `health-services/resource-generator/src/main/java/org/egov/processor/util/PlanUtil.java`

1. **Method: `create`**
   - **Description**: Creates a plan configuration request, builds a plan request from it, and pushes it to the messaging system for further processing.
   - **Parameters**: 
     - `PlanConfigurationRequest planConfigurationRequest`: The plan configuration request.
     - `JsonNode feature`: The feature JSON node.
     - `Map<String, BigDecimal> resultMap`: The result map.
     - `Map<String, Object> boundaryCodeToCensusAdditionalDetails`: A Map of boundary code to censusAdditionalDetails for that boundary code.
   ```java
   public void create(PlanConfigurationRequest planConfigurationRequest, JsonNode feature, Map<String, BigDecimal> resultMap, Map<String, Object> boundaryCodeToCensusAdditionalDetails) {
       // Implementation...
   }
   ```

#### From `health-services/resource-generator/src/main/java/org/egov/processor/util/EnrichmentUtil.java`

1. **Method: `enrichResourceMapping`**
   - **Description**: Enriches the `PlanConfiguration` with resource mappings based on MDMS data and locale messages.
   - **Parameters**: 
     - `PlanConfigurationRequest request`: The request containing the configuration to enrich.
     - `LocaleResponse localeResponse`: The response containing locale messages.
     - `String campaignType`: The campaign type identifier.
     - `String fileStoreId`: The associated file store ID.
   ```java
   public void enrichResourceMapping(PlanConfigurationRequest request, LocaleResponse localeResponse, String campaignType, String fileStoreId) {
       // Implementation...
   }
   ```

#### From `health-services/plan-service/src/main/java/digit/service/validator/PlanConfigurationValidator.java`

1. **Method: `validateAssumptionKeyAgainstMDMS`**
   - **Description**: Validates the assumption keys against MDMS data.
   - **Parameters**: 
     - `PlanConfigurationRequest request`: The request containing the plan configuration and the MDMS data.
     - `Object mdmsData`: The MDMS data.
   ```java
   public void validateAssumptionKeyAgainstMDMS(PlanConfigurationRequest request, Object mdmsData) {
       // Implementation...
   }
   ```

These snippets provide context on how plan configurations are managed and validated, which may relate to the user's comment about annotations present in the model.

### Relevant Code Snippets

#### From `health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java`

**Line 42-898: `ExcelParser` Class**
```java
@Slf4j
@Service
public class ExcelParser implements FileParser {
    // Class members and constructor omitted for brevity

    /**
     * Parses file data, extracts information from the file, and processes it.
     *
     * @param planConfigurationRequest The plan configuration request containing
     *                                 necessary information for parsing the file.
     * @param fileStoreId              The ID of the file in the file store.
     * @param campaignResponse         The response object to be updated with parsed
     *                                 data.
     * @return The parsed and processed data.
     */
    @Override
    public Object parseFileData(PlanConfigurationRequest planConfigurationRequest, String fileStoreId,
                                Object campaignResponse) {
        // Implementation omitted for brevity
    }

    /**
     * Processes an Excel file, extracts data, and updates campaign details and
     * resources.
     *
     * @param planConfigurationRequest The plan configuration request containing
     *                                 necessary information for processing the
     *                                 file.
     * @param file                     The Excel file to be processed.
     * @param fileStoreId              The ID of the file in the file store.
     * @param campaignResponse         The response object to be updated with
     *                                 processed data.
     */
    private void processExcelFile(PlanConfigurationRequest planConfigurationRequest, File file, String fileStoreId,
            Object campaignResponse) {
        // Implementation omitted for brevity
    }

    // Additional methods omitted for brevity
}
```
- **Description**: This class is responsible for parsing Excel files related to plan configurations. It includes methods for processing file data and handling campaign responses.

#### From `health-services/libraries/health-services-common/src/main/java/org/egov/common/utils/CommonUtils.java`

**Line 46-1159: `CommonUtils` Class**
```java
@Slf4j
public class CommonUtils {
    // Class members and methods omitted for brevity

    /**
     * Retrieves audit details for creating an entity.
     * This method generates audit details including creation and last modified timestamps.
     *
     * @param requestInfo The request information containing user details.
     * @return The audit details for create operation.
     */
    public static AuditDetails getAuditDetailsForCreate(RequestInfo requestInfo) {
        log.info("Creating audit details for create api");
        Long time = System.currentTimeMillis();
        return AuditDetails.builder()
                .createdBy(requestInfo.getUserInfo().getUuid())
                .createdTime(time)
                .lastModifiedBy(requestInfo.getUserInfo().getUuid())
                .lastModifiedTime(time)
                .build();
    }

    // Additional methods omitted for brevity
}
```
- **Description**: This utility class provides common functionalities, including generating audit details for create operations, which may be relevant for handling entities with annotations in their models.

### Summary
The snippets from `ExcelParser` and `CommonUtils` provide context on how files are processed and how audit details are generated, which may relate to the user's comment about annotations present in the model.

</details>


---

<details>
<summary>✏️ Learnings added</summary>

```
Learnt from: Priyanka-eGov
PR: egovernments/health-campaign-services#1482
File: health-services/resource-generator/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java:70-87
Timestamp: 2025-04-03T05:22:38.476Z
Learning: The DraftRequest and DraftDetails model classes in health-services/resource-generator/src/main/java/org/egov/processor/web/models/ have Bean Validation annotations (@Valid, @NotNull, @Size) that handle null validation automatically, making explicit null checks in service methods redundant.
```

---

```
Learnt from: Priyanka-eGov
PR: egovernments/health-campaign-services#1482
File: health-services/resource-generator/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java:70-87
Timestamp: 2025-04-03T05:22:38.477Z
Learning: The DraftRequest and DraftDetails model classes in health-services/resource-generator have Bean Validation annotations (@Valid, @NotNull, @Size) that validate user input at the framework level, making explicit null checks in service methods like buildPlanConfigurationSearchRequest redundant.
```

> Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure [review instructions](https://docs.coderabbit.ai/guides/review-instructions). You can manage existing learnings in the [app](https://app.coderabbit.ai/learnings).

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-04-03T05:22:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -63,4 +66,63 @@
     public void orderPlanConfigurationOperations(PlanConfigurationRequest planConfigurationRequest) {
         planConfigurationRequest.getPlanConfiguration().getOperations().sort(Comparator.comparingInt(Operation::getExecutionOrder));
     }
+
+    /**
+     * Builds a PlanConfigurationSearchRequest using information from the DraftRequest,
+     * including the plan configuration ID, tenant ID, and request info.
+     *
+     * @param draftRequest the DraftRequest containing search details
+     * @return a PlanConfigurationSearchRequest with the search criteria and request info
+     */
+    public PlanConfigurationSearchRequest buildPlanConfigurationSearchRequest(DraftRequest draftRequest) {
+        PlanConfigurationSearchCriteria searchCriteria = PlanConfigurationSearchCriteria.builder()
+                .id(draftRequest.getDraftDetails().getPlanConfigurationId())
+                .tenantId(draftRequest.getDraftDetails().getTenantId())
+                .build();
+
+        return PlanConfigurationSearchRequest.builder()
+                .requestInfo(draftRequest.getRequestInfo())
+                .planConfigurationSearchCriteria(searchCriteria)
+                .build();
+    }
+
+    /**
+     * Sets the filestore ID for the file with template identifier "ESTIMATIONS_IN_PROGRESS".
+     * If the file exists, the filestore ID is updated. If the file does not exist, a new file is added
+     * with the specified filestore ID and input file type.
+     *
+     * @param planConfigurationRequest the plan configuration request containing the list of files
+     * @param fileStoreId the filestore ID to set or add
+     * @param inputFileType the input file type for the new file if added
+     */
+    public void setOrAddFileForDraft(PlanConfigurationRequest planConfigurationRequest, String fileStoreId,
+                                                     File.InputFileTypeEnum inputFileType) {
+        List<File> files = planConfigurationRequest.getPlanConfiguration().getFiles();
+
+        // Check if file with the specified templateIdentifier exists
+        File existingFile = files.stream()
+                .filter(file -> FILE_TEMPLATE_IDENTIFIER_DRAFT_INPROGRESS.equals(file.getTemplateIdentifier()))
+                .findFirst()
+                .orElse(null);
+
+        if (!ObjectUtils.isEmpty(existingFile)) {
+            // If the file exists, update the filestoreId and change template identifier to Draft Complete
+            existingFile.setFilestoreId(fileStoreId);
+            existingFile.setTemplateIdentifier(FILE_TEMPLATE_IDENTIFIER_DRAFT_COMPLETE);
+        } else {
+            // If the file doesn't exist, add a new file
+            File estimationFile = File.builder()
+                    .filestoreId(fileStoreId)
+                    .inputFileType(inputFileType)
+                    .templateIdentifier(FILE_TEMPLATE_IDENTIFIER_DRAFT_COMPLETE)
+                    .active(true)
+                    .build();
+            files.add(estimationFile);
+        }
+
+        // Set workflow to null as in the original methods
+        planConfigurationRequest.getPlanConfiguration().setWorkflow(null);
+    }
path: health-services/resource-generator/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java
user: login: coderabbitai[bot]
body: @Priyanka-eGov Thanks for confirming! The added validation and improved comments should make the code more robust and maintainable. Let me know if you need any further assistance with this PR.

---

<details>
<summary>🧬 Code Definitions Used</summary>

### Relevant Code Snippets for `PlanConfigurationUtil.java`

#### 1. `health-services/plan-service/src/main/java/digit/util/MdmsV2Util.java`
```java
@Slf4j
@Component
public class MdmsV2Util {
    // ... (constructor and other methods)

    /**
     * Fetches MDMS V2 data based on the provided request information, tenant ID, schema code, and unique identifier.
     *
     * @param requestInfo      The request information object containing metadata about the request.
     * @param tenantId         The tenant ID for which MDMS data is to be retrieved.
     * @param schemaCode       The schema code from where mdms data is to be fetched.
     * @param uniqueIdentifier A unique identifier to filter the MDMS data (optional).
     * @return A list of {@link Mdms} objects containing the fetched MDMS data.
     * @throws CustomException If no MDMS data is found for the given tenant.
     */
    public List<Mdms> fetchMdmsV2Data(RequestInfo requestInfo, String tenantId, String schemaCode, String uniqueIdentifier) {
        // ... (method implementation)
    }
}
```

#### 2. `health-services/plan-service/src/main/java/digit/util/PlanEmployeeAssignmentUtil.java`
```java
@Slf4j
@Component
public class PlanEmployeeAssignmentUtil {
    // ... (constructor and other methods)

    /**
     * Fetches a list of MixedStrategyOperationLogic objects from MDMS based on the provided planConfigurationRequest.
     *
     * @param request The PlanConfigurationRequest containing the plan configuration and request info.
     * @return A list of MixedStrategyOperationLogic objects fetched from MDMS.
     */
    public List<MixedStrategyOperationLogic> fetchMixedStrategyOperationLogicFromMDMS(PlanConfigurationRequest request) {
        // ... (method implementation)
    }
}
```

#### 3. `health-services/plan-service/src/main/java/digit/util/PlanUtil.java`
```java
@Slf4j
@Component
public class PlanUtil {
    // ... (constructor and other methods)

    /**
     * Fetches plan configurations based on the provided search request.
     *
     * @param planConfigurationSearchRequest The search request containing the search criteria.
     * @return A response with a list of plan configurations that matches the search criteria.
     */
    public PlanConfigurationResponse fetchPlanConfigurations(PlanConfigurationSearchRequest planConfigurationSearchRequest) {
        // ... (method implementation)
    }
}
```

#### 4. `health-services/plan-service/src/main/java/digit/service/PlanService.java`
```java
@Slf4j
@Service
public class PlanService {
    // ... (constructor and other methods)

    /**
     * Searches for plans based on the provided search criteria.
     *
     * @param searchRequest The search request containing the criteria for searching plans.
     * @return A response containing the list of plans that match the search criteria.
     */
    public PlanResponse searchPlan(PlanSearchRequest searchRequest) {
        // ... (method implementation)
    }
}
```

#### 5. `health-services/plan-service/src/main/java/digit/service/PlanConfigurationService.java`
```java
@Slf4j
@Service
public class PlanConfigurationService {
    // ... (constructor and other methods)

    /**
     * Updates the plan configuration based on the provided request.
     *
     * @param request The request containing the updated plan configuration details.
     */
    public void update(PlanConfigurationRequest request) {
        // ... (method implementation)
    }
}
```

### Summary
The snippets provided above are relevant to the `PlanConfigurationUtil.java` file as they involve fetching and processing plan configurations, which is a core functionality of the `PlanConfigurationUtil` class. The methods in these snippets demonstrate how to interact with MDMS and other services to retrieve and manipulate plan-related data, which is essential for the operations defined in `PlanConfigurationUtil`.

### Relevant Code Snippets for `PlanConfigurationUtil.java`

#### 1. **ErrorConstants.java** (Lines 5-71)
```java
@Component
public class ErrorConstants {
    public static final String ERROR_WHILE_FETCHING_FROM_PLAN_SERVICE = "Exception occurred while fetching plan configuration from plan service ";
}
```
- **Description**: This constant is used in the `PlanConfigurationUtil` class to log errors when fetching plan configurations from the plan service.

#### 2. **ServiceConstants.java** (Lines 7-121)
```java
@Component
public class ServiceConstants {
    public static final String FILE_TEMPLATE_IDENTIFIER_DRAFT_COMPLETE = "DraftComplete";
    public static final String FILE_TEMPLATE_IDENTIFIER_DRAFT_INPROGRESS = "DraftInprogress";
}
```
- **Description**: These constants are used in the `setOrAddFileForDraft` method of `PlanConfigurationUtil` to identify file templates for draft statuses.

#### 3. **FilestoreUtil.java** (Lines 30-206)
```java
@Component
@Slf4j
public class FilestoreUtil {
    public byte[] getFileByteArray(String tenantId, String fileStoreId) {
        // Method to retrieve a file from the file store service
    }
}
```
- **Description**: This utility class provides methods to interact with the file store service, which may be relevant for handling files associated with plan configurations.

#### 4. **CensusUtil.java** (Lines 27-228)
```java
@Component
@Slf4j
public class CensusUtil {
    public void create(PlanConfigurationRequest planConfigurationRequest, JsonNode feature, Map<String, String> mappedValues, String heirarchyType) {
        // Method to create a census record based on the plan configuration request
    }
}
```
- **Description**: This class is responsible for creating census records, which may be relevant when dealing with plan configurations that involve census data.

#### 5. **PlanConfigQueryBuilder.java** (Lines 14-184)
```java
@Component
public class PlanConfigQueryBuilder {
    public String getPlanConfigSearchQuery(PlanConfigurationSearchCriteria criteria, List<Object> preparedStmtList) {
        // Method to construct a SQL query for searching plan configurations
    }
}
```
- **Description**: This class constructs SQL queries for searching plan configurations, which is relevant for the `search` method in `PlanConfigurationUtil`.

#### 6. **PlanRepositoryImpl.java** (Lines 25-209)
```java
@Slf4j
@Repository
public class PlanRepositoryImpl implements PlanRepository {
    public List<Plan> search(PlanSearchCriteria planSearchCriteria) {
        // Method to search for plans based on criteria
    }
}
```
- **Description**: This repository class provides methods to search for plans, which may be relevant when fetching plan configurations.

#### 7. **PlanRowMapper.java** (Lines 19-250)
```java
@Component
public class PlanRowMapper implements ResultSetExtractor<List<Plan>> {
    @Override
    public List<Plan> extractData(ResultSet rs) throws SQLException, DataAccessException {
        // Method to map ResultSet to Plan objects
    }
}
```
- **Description**: This class maps database rows to `Plan` objects, which is relevant for understanding how plan data is retrieved from the database.

#### 8. **PlanConfigRowMapper.java** (Lines 18-230)
```java
@Component
public class PlanConfigRowMapper implements ResultSetExtractor<List<PlanConfiguration>> {
    @Override
    public List<PlanConfiguration> extractData(ResultSet rs) throws SQLException, DataAccessException {
        // Method to map ResultSet to PlanConfiguration objects
    }
}
```
- **Description**: Similar to `PlanRowMapper`, this class maps database rows to `PlanConfiguration` objects, which is crucial for understanding how configurations are retrieved.

#### 9. **CensusQueryBuilder.java** (Lines 13-221)
```java
@Component
public class CensusQueryBuilder {
    public String getCensusSearchQuery(CensusSearchCriteria censusSearchCriteria, List<Object> preparedStmtList) {
        // Method to construct a SQL query for searching census records
    }
}
```
- **Description**: This class constructs SQL queries for searching census records, which may be relevant when dealing with census data in plan configurations.

#### 10. **CensusRepositoryImpl.java** (Lines 24-219)
```java
@Slf4j
@Repository
public class CensusRepositoryImpl implements CensusRepository {
    public List<Census> search(CensusSearchCriteria censusSearchCriteria) {
        // Method to search for census records based on criteria
    }
}
```
- **Description**: This repository class provides methods to search for census records, which may be relevant when fetching census data associated with plan configurations.

### Summary
The snippets provided above are relevant to understanding the `PlanConfigurationUtil.java` file and addressing the user comment. They include constants for error handling, utility methods for file and census management, and query builders for fetching plan configurations and census records.

### Relevant Code Snippets for `PlanConfigurationUtil.java`

#### 1. `OutputEstimationGenerationUtil.java`
- **Line Range:** 22-293
- **Summary:**
  ```java
  /**
   * Processes an output Excel workbook by removing unnecessary sheets, localizing header columns,
   * and adding facility information for each boundary code. The configuration for processing
   * is based on the provided PlanConfigurationRequest.
   *
   * @param workbook   the Excel workbook to process
   * @param request    the PlanConfigurationRequest containing processing configuration
   * @param filestoreId the identifier of the file store for additional processing requirements
   */
  public void processOutputFile(Workbook workbook, PlanConfigurationRequest request, String filestoreId) {
      // Implementation details...
  }
  ```

#### 2. `PlanUtil.java`
- **Line Range:** 32-322
- **Summary:**
  ```java
  /**
   * Creates a plan configuration request, builds a plan request from it, and pushes it to the messaging system for further processing.
   * 
   * @param planConfigurationRequest The plan configuration request.
   * @param feature The feature JSON node.
   * @param resultMap The result map.
   * @param boundaryCodeToCensusAdditionalDetails A Map of boundary code to censusAdditionalDetails for that boundary code.
   */
  public void create(PlanConfigurationRequest planConfigurationRequest, JsonNode feature,
          Map<String, BigDecimal> resultMap, Map<String, Object> boundaryCodeToCensusAdditionalDetails) {
      // Implementation details...
  }
  ```

#### 3. `PlanFacilityValidator.java`
- **Line Range:** 28-286
- **Summary:**
  ```java
  /**
   * This method validates the Plan Facility Create request.
   * It performs multiple validations such as plan configuration, facility existence,
   * and campaign-related validations.
   *
   * @param planFacilityRequest The plan facility request to be validated.
   */
  public void validatePlanFacilityCreate(PlanFacilityRequest planFacilityRequest) {
      // Implementation details...
  }
  ```

#### 4. `CommonUtil.java`
- **Line Range:** 28-322
- **Summary:**
  ```java
  /**
   * Validates the user information within the provided PlanConfigurationRequest.
   *
   * @param requestInfo the request info containing the user information to be validated
   * @throws CustomException if the user information is missing in the request
   */
  public void validateUserInfo(RequestInfo requestInfo) {
      // Implementation details...
  }
  ```

#### 5. `PlanConfigurationValidator.java`
- **Line Range:** 28-575
- **Summary:**
  ```java
  /**
   * Validates the create request for plan configuration, including assumptions against MDMS data.
   *
   * @param request The create request for plan configuration.
   */
  public void validateCreate(PlanConfigurationRequest request) {
      // Implementation details...
  }
  ```

#### 6. `PlanValidator.java`
- **Line Range:** 27-670
- **Summary:**
  ```java
  /**
   * This method performs business validations on plan create requests
   *
   * @param request
   */
  public void validatePlanCreate(PlanRequest request) {
      // Implementation details...
  }
  ```

#### 7. `ProjectValidator.java`
- **Line Range:** 45-652
- **Summary:**
  ```java
  /* Validates create Project request body */
  public void validateCreateProjectRequest(ProjectRequest request) {
      // Implementation details...
  }
  ```

These snippets provide relevant context and functionality that may assist in understanding or addressing the user comment related to the `PlanConfigurationUtil.java` file.

### Relevant Code Snippets

#### From `health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java`

**Line 42-898: `ExcelParser` Class**
```java
@Slf4j
@Service
public class ExcelParser implements FileParser {
    // Class members and constructor omitted for brevity

    /**
     * Parses file data, extracts information from the file, and processes it.
     *
     * @param planConfigurationRequest The plan configuration request containing
     *                                 necessary information for parsing the file.
     * @param fileStoreId              The ID of the file in the file store.
     * @param campaignResponse         The response object to be updated with parsed
     *                                 data.
     * @return The parsed and processed data.
     */
    @Override
    public Object parseFileData(PlanConfigurationRequest planConfigurationRequest, String fileStoreId,
                                Object campaignResponse) {
        // Method implementation omitted for brevity
    }

    /**
     * Processes an Excel file, extracts data, and updates campaign details and
     * resources.
     *
     * @param planConfigurationRequest The plan configuration request containing
     *                                 necessary information for processing the
     *                                 file.
     * @param file                     The Excel file to be processed.
     * @param fileStoreId              The ID of the file in the file store.
     * @param campaignResponse         The response object to be updated with
     *                                 processed data.
     */
    private void processExcelFile(PlanConfigurationRequest planConfigurationRequest, File file, String fileStoreId,
            Object campaignResponse) {
        // Method implementation omitted for brevity
    }

    /**
     * Processes each sheet in the workbook for plan configuration data.
     * Validates column names, processes rows, and integrates campaign details.
     * 
     * @param request The request containing configuration details including tenant ID.
     * @param fileStoreId The ID of the uploaded file in the file store.
     * @param campaignResponse The response object containing campaign details.
     * @param excelWorkbook The workbook containing sheets to be processed.
     */
    private void processSheets(PlanConfigurationRequest request, String fileStoreId,
                               Object campaignResponse, Workbook excelWorkbook) {
        // Method implementation omitted for brevity
    }

    // Additional methods omitted for brevity
}
```

#### From `health-services/libraries/health-services-common/src/main/java/org/egov/common/utils/CommonUtils.java`

**Line 46-1159: `CommonUtils` Class**
```java
@Slf4j
public class CommonUtils {
    // Class members and methods omitted for brevity

    /**
     * Retrieves audit details for creating an entity.
     * This method generates audit details including creation and last modified timestamps.
     *
     * @param requestInfo The request information containing user details.
     * @return The audit details for create operation.
     */
    public static AuditDetails getAuditDetailsForCreate(RequestInfo requestInfo) {
        // Method implementation omitted for brevity
    }

    /**
     * Get auditDetails having only the lastModifiedBy and lastModifiedTime fields set.
     *
     * @param existingAuditDetails is the audit details coming from request.
     * @param modifiedByUuid is the uuid of the user performing this update.
     * @return auditDetails
     */
    public static AuditDetails getAuditDetailsForUpdate(AuditDetails existingAuditDetails, String modifiedByUuid) {
        // Method implementation omitted for brevity
    }

    // Additional methods omitted for brevity
}
```

### Summary of Relevant Snippets
1. **ExcelParser Class**: Contains methods for parsing Excel files and processing plan configuration data, which may relate to the functionality of `PlanConfigurationUtil`.
2. **CommonUtils Class**: Provides utility methods for handling audit details, which could be relevant for operations involving entity creation and updates in the context of plan configurations.

</details>



<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-04-03T05:23:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -75,6 +75,35 @@ public void processOutputFile(Workbook workbook, PlanConfigurationRequest reques
 
     }
 
+    /**
+     * Processes an output Excel workbook by removing unnecessary sheets, localizing header columns
+     * for each boundary code. The configuration for processing
+     * is based on the provided PlanConfigurationRequest.
+     *
+     * @param workbook   the Excel workbook to process
+     * @param request    the PlanConfigurationRequest containing processing configuration
+     */
+    public void processDraftOutputFile(Workbook workbook, PlanConfigurationRequest request) {
+        LocaleResponse localeResponse = localeUtil.searchLocale(request);
+        Map<String, Object> mdmsDataForCommonConstants = mdmsUtil.fetchMdmsDataForCommonConstants(
+                request.getRequestInfo(),
+                request.getPlanConfiguration().getTenantId());
+
+        // 1. removing readme sheet
+        for (int i = workbook.getNumberOfSheets() - 1; i >= 0; i--) {
+            Sheet sheet = workbook.getSheetAt(i);
+            if (!isSheetAllowedToProcess(sheet.getSheetName(), localeResponse, mdmsDataForCommonConstants)) {
+                workbook.removeSheetAt(i);
+            }
+        }
+
+        // 2. Stylize and localize output column headers
+        for(Sheet sheet: workbook) {
+            processSheetForHeaderLocalization(sheet, localeResponse);
+        }
+
+    }
path: health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java
user: login: Priyanka-eGov
body: done

created_at: 2025-04-03T05:41:00Z
author_association: COLLABORATOR
diff_hunk: @@ -75,6 +75,35 @@ public void processOutputFile(Workbook workbook, PlanConfigurationRequest reques
 
     }
 
+    /**
+     * Processes an output Excel workbook by removing unnecessary sheets, localizing header columns
+     * for each boundary code. The configuration for processing
+     * is based on the provided PlanConfigurationRequest.
+     *
+     * @param workbook   the Excel workbook to process
+     * @param request    the PlanConfigurationRequest containing processing configuration
+     */
+    public void processDraftOutputFile(Workbook workbook, PlanConfigurationRequest request) {
+        LocaleResponse localeResponse = localeUtil.searchLocale(request);
+        Map<String, Object> mdmsDataForCommonConstants = mdmsUtil.fetchMdmsDataForCommonConstants(
+                request.getRequestInfo(),
+                request.getPlanConfiguration().getTenantId());
+
+        // 1. removing readme sheet
+        for (int i = workbook.getNumberOfSheets() - 1; i >= 0; i--) {
+            Sheet sheet = workbook.getSheetAt(i);
+            if (!isSheetAllowedToProcess(sheet.getSheetName(), localeResponse, mdmsDataForCommonConstants)) {
+                workbook.removeSheetAt(i);
+            }
+        }
+
+        // 2. Stylize and localize output column headers
+        for(Sheet sheet: workbook) {
+            processSheetForHeaderLocalization(sheet, localeResponse);
+        }
+
+    }
path: health-services/resource-generator/src/main/java/org/egov/processor/util/OutputEstimationGenerationUtil.java
user: login: coderabbitai[bot]
body: @Priyanka-eGov Great! Thank you for implementing the refactoring to remove the code duplication. This change will make the codebase more maintainable and easier to update in the future.

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-04-03T05:41:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,25 @@
+package org.egov.processor.web.controllers;
+
+import jakarta.validation.Valid;
+import org.egov.processor.service.DraftService;
+import org.egov.processor.web.models.DraftRequest;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+@Controller
+public class DraftController {
+
+    private DraftService draftService;
+
+    public DraftController(DraftService draftService) {
+        this.draftService = draftService;
+    }
+
+    @PostMapping("/draft")
+    public ResponseEntity<String> createDraftMicroplan(@RequestBody @Valid DraftRequest draftRequest) {
+        draftService.createDraftPlans(draftRequest);
+        return ResponseEntity.ok("Draft processing started successfully.");
+    }
path: health-services/resource-generator/src/main/java/org/egov/processor/web/controllers/DraftController.java
user: login: Priyanka-eGov
body: done
created_at: 2025-04-03T05:43:56Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,25 @@
+package org.egov.processor.web.controllers;
+
+import jakarta.validation.Valid;
+import org.egov.processor.service.DraftService;
+import org.egov.processor.web.models.DraftRequest;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+@Controller
+public class DraftController {
+
+    private DraftService draftService;
+
+    public DraftController(DraftService draftService) {
+        this.draftService = draftService;
+    }
+
+    @PostMapping("/draft")
+    public ResponseEntity<String> createDraftMicroplan(@RequestBody @Valid DraftRequest draftRequest) {
+        draftService.createDraftPlans(draftRequest);
+        return ResponseEntity.ok("Draft processing started successfully.");
+    }
path: health-services/resource-generator/src/main/java/org/egov/processor/web/controllers/DraftController.java
user: login: coderabbitai[bot]
body: @Priyanka-eGov Great! Thanks for implementing the change. Using HTTP 202 Accepted for asynchronous operations is indeed the right approach.
---

<details>
<summary>✏️ Learnings added</summary>

```
Learnt from: Priyanka-eGov
PR: egovernments/health-campaign-services#1482
File: health-services/resource-generator/src/main/java/org/egov/processor/web/controllers/DraftController.java:0-0
Timestamp: 2025-04-03T05:44:18.863Z
Learning: When implementing REST endpoints that trigger asynchronous operations, use HTTP 202 Accepted status code (ResponseEntity.accepted()) instead of HTTP 200 OK to properly indicate that the request has been accepted for processing but is not yet complete.
```

> Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure [review instructions](https://docs.coderabbit.ai/guides/review-instructions). You can manage existing learnings in the [app](https://app.coderabbit.ai/learnings).

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-04-03T05:44:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,112 @@
+package org.egov.processor.service;
+
+import org.apache.poi.ss.usermodel.Workbook;
+import org.egov.processor.util.*;
+import org.egov.processor.web.models.*;
+import org.egov.processor.web.models.campaignManager.CampaignResponse;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.egov.processor.config.ServiceConstants.FILE_TEMPLATE_IDENTIFIER_POPULATION;
+import static org.egov.processor.web.models.File.InputFileTypeEnum.EXCEL;
+
+@Service
+public class DraftService {
+
+    private PlanConfigurationUtil planConfigurationUtil;
+
+    private ExcelParser excelParser;
+
+    private ParsingUtil parsingUtil;
+
+    private PlanUtil planUtil;
+
+    private CampaignIntegrationUtil campaignIntegrationUtil;
+
+    private MdmsUtil mdmsUtil;
+
+    private LocaleUtil localeUtil;
+
+    private EnrichmentUtil enrichmentUtil;
+
+    private OutputEstimationGenerationUtil outputEstimationGenerationUtil;
+
+
+    public DraftService(PlanConfigurationUtil planConfigurationUtil, ExcelParser excelParser, ParsingUtil parsingUtil, PlanUtil planUtil, CampaignIntegrationUtil campaignIntegrationUtil, MdmsUtil mdmsUtil, LocaleUtil localeUtil, EnrichmentUtil enrichmentUtil, OutputEstimationGenerationUtil outputEstimationGenerationUtil) {
+        this.planConfigurationUtil = planConfigurationUtil;
+        this.excelParser = excelParser;
+        this.parsingUtil = parsingUtil;
+        this.planUtil = planUtil;
+        this.campaignIntegrationUtil = campaignIntegrationUtil;
+        this.mdmsUtil = mdmsUtil;
+        this.localeUtil = localeUtil;
+        this.enrichmentUtil = enrichmentUtil;
+        this.outputEstimationGenerationUtil = outputEstimationGenerationUtil;
+    }
+
+    @Async
+    public void createDraftPlans(DraftRequest draftRequest) {
+        // Retrieve Plan Configuration
+        List<PlanConfiguration> planConfigurationList = planConfigurationUtil.search(planConfigurationUtil.buildPlanConfigurationSearchRequest(draftRequest));
+        PlanConfigurationRequest request = PlanConfigurationRequest.builder()
+                .requestInfo(draftRequest.getRequestInfo())
+                .planConfiguration(planConfigurationList.get(0))
+                .build();
+
+        // Get filestoreId for population template
+        String fileStoreId = getFilestoreIdForPopulationTemplate(request.getPlanConfiguration());
+
+        // Retrieve data and perform actions
+        Workbook workbook = excelParser.getWorkbookFromFilestoreId(fileStoreId, request.getPlanConfiguration().getTenantId());
+        Object campaignSearchResponse = campaignIntegrationUtil.performCampaignSearch(request);
+        CampaignResponse campaign = campaignIntegrationUtil.parseCampaignResponse(campaignSearchResponse);
+        LocaleResponse localeResponse = localeUtil.searchLocale(request);
+        Object mdmsData = mdmsUtil.fetchMdmsData(request.getRequestInfo(), request.getPlanConfiguration().getTenantId());
+
path: health-services/resource-generator/src/main/java/org/egov/processor/service/DraftService.java
user: login: Priyanka-eGov
body: Added exception in parseCampaignResponse() func
created_at: 2025-04-03T05:56:02Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,112 @@
+package org.egov.processor.service;
+
+import org.apache.poi.ss.usermodel.Workbook;
+import org.egov.processor.util.*;
+import org.egov.processor.web.models.*;
+import org.egov.processor.web.models.campaignManager.CampaignResponse;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.egov.processor.config.ServiceConstants.FILE_TEMPLATE_IDENTIFIER_POPULATION;
+import static org.egov.processor.web.models.File.InputFileTypeEnum.EXCEL;
+
+@Service
+public class DraftService {
+
+    private PlanConfigurationUtil planConfigurationUtil;
+
+    private ExcelParser excelParser;
+
+    private ParsingUtil parsingUtil;
+
+    private PlanUtil planUtil;
+
+    private CampaignIntegrationUtil campaignIntegrationUtil;
+
+    private MdmsUtil mdmsUtil;
+
+    private LocaleUtil localeUtil;
+
+    private EnrichmentUtil enrichmentUtil;
+
+    private OutputEstimationGenerationUtil outputEstimationGenerationUtil;
+
+
+    public DraftService(PlanConfigurationUtil planConfigurationUtil, ExcelParser excelParser, ParsingUtil parsingUtil, PlanUtil planUtil, CampaignIntegrationUtil campaignIntegrationUtil, MdmsUtil mdmsUtil, LocaleUtil localeUtil, EnrichmentUtil enrichmentUtil, OutputEstimationGenerationUtil outputEstimationGenerationUtil) {
+        this.planConfigurationUtil = planConfigurationUtil;
+        this.excelParser = excelParser;
+        this.parsingUtil = parsingUtil;
+        this.planUtil = planUtil;
+        this.campaignIntegrationUtil = campaignIntegrationUtil;
+        this.mdmsUtil = mdmsUtil;
+        this.localeUtil = localeUtil;
+        this.enrichmentUtil = enrichmentUtil;
+        this.outputEstimationGenerationUtil = outputEstimationGenerationUtil;
+    }
+
+    @Async
+    public void createDraftPlans(DraftRequest draftRequest) {
+        // Retrieve Plan Configuration
+        List<PlanConfiguration> planConfigurationList = planConfigurationUtil.search(planConfigurationUtil.buildPlanConfigurationSearchRequest(draftRequest));
+        PlanConfigurationRequest request = PlanConfigurationRequest.builder()
+                .requestInfo(draftRequest.getRequestInfo())
+                .planConfiguration(planConfigurationList.get(0))
+                .build();
+
+        // Get filestoreId for population template
+        String fileStoreId = getFilestoreIdForPopulationTemplate(request.getPlanConfiguration());
+
+        // Retrieve data and perform actions
+        Workbook workbook = excelParser.getWorkbookFromFilestoreId(fileStoreId, request.getPlanConfiguration().getTenantId());
+        Object campaignSearchResponse = campaignIntegrationUtil.performCampaignSearch(request);
+        CampaignResponse campaign = campaignIntegrationUtil.parseCampaignResponse(campaignSearchResponse);
+        LocaleResponse localeResponse = localeUtil.searchLocale(request);
+        Object mdmsData = mdmsUtil.fetchMdmsData(request.getRequestInfo(), request.getPlanConfiguration().getTenantId());
+
path: health-services/resource-generator/src/main/java/org/egov/processor/service/DraftService.java
user: login: coderabbitai[bot]
body: <details>
<summary>🧩 Analysis chain</summary>

🏁 Script executed:
```
#!/bin/bash
# Let's find the implementation of parseCampaignResponse function
grep -r "parseCampaignResponse" --include="*.java" .
```

Length of output: 845

---

🏁 Script executed:
```
#!/bin/bash
# Get the implementation of parseCampaignResponse method in CampaignIntegrationUtil.java
cat ./health-services/resource-generator/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java
```

Length of output: 9078

---



</details>

@Priyanka-eGov Thanks for adding exception handling to the parseCampaignResponse() function. I looked at the current implementation and don't see the changes yet. Could you share more details about how you implemented the exception handling to prevent the potential IndexOutOfBoundsException when accessing campaign.getCampaign().get(0)?

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-04-03T05:56:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,25 @@
+package org.egov.processor.web.controllers;
+
+import jakarta.validation.Valid;
+import org.egov.processor.service.DraftService;
+import org.egov.processor.web.models.DraftRequest;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+@Controller
+public class DraftController {
+
+    private DraftService draftService;
+
+    public DraftController(DraftService draftService) {
+        this.draftService = draftService;
+    }
+
+    @PostMapping("/draft")
+    public ResponseEntity<String> createDraftMicroplan(@RequestBody @Valid DraftRequest draftRequest) {
+        draftService.createDraftPlans(draftRequest);
+        return ResponseEntity.ok("Draft processing started successfully.");
+    }
+}
path: health-services/resource-generator/src/main/java/org/egov/processor/web/controllers/DraftController.java
user: login: Priyanka-eGov
body: done
created_at: 2025-04-03T05:58:53Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,25 @@
+package org.egov.processor.web.controllers;
+
+import jakarta.validation.Valid;
+import org.egov.processor.service.DraftService;
+import org.egov.processor.web.models.DraftRequest;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+@Controller
+public class DraftController {
+
+    private DraftService draftService;
+
+    public DraftController(DraftService draftService) {
+        this.draftService = draftService;
+    }
+
+    @PostMapping("/draft")
+    public ResponseEntity<String> createDraftMicroplan(@RequestBody @Valid DraftRequest draftRequest) {
+        draftService.createDraftPlans(draftRequest);
+        return ResponseEntity.ok("Draft processing started successfully.");
+    }
+}
path: health-services/resource-generator/src/main/java/org/egov/processor/web/controllers/DraftController.java
user: login: coderabbitai[bot]
body: <details>
<summary>🧩 Analysis chain</summary>

@Priyanka-eGov Thanks for confirming that you've implemented the changes. Let me check the latest version of the `DraftController` to verify the implementation.

---

🏁 Script executed:
```
#!/bin/bash
# Check if the DraftController file has been updated with the suggested changes
cat health-services/resource-generator/src/main/java/org/egov/processor/web/controllers/DraftController.java
```

Length of output: 976

---



</details>

@Priyanka-eGov Great! I see you've updated the endpoint to use `ResponseEntity.accepted()` instead of `ResponseEntity.ok()`, which is the correct approach for asynchronous operations. This properly indicates that the request has been accepted for processing but is not yet complete (HTTP 202 status code).

---

<details>
<summary>🧠 Learnings used</summary>

```
Learnt from: Priyanka-eGov
PR: egovernments/health-campaign-services#1482
File: health-services/resource-generator/src/main/java/org/egov/processor/web/controllers/DraftController.java:0-0
Timestamp: 2025-04-03T05:44:18.983Z
Learning: When implementing REST endpoints that trigger asynchronous operations, use HTTP 202 Accepted status code (ResponseEntity.accepted()) instead of HTTP 200 OK to properly indicate that the request has been accepted for processing but is not yet complete.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-04-03T05:59:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -31,6 +31,20 @@
 		this.mapper = mapper;
 	}
 
+	/**
+	 * Performs a campaign search based on the provided plan configuration request.
+	 * This method builds a campaign search request using the integration utility,
+	 * fetches the search result from the service request repository, and returns it.
+	 *
+	 * @param planConfigurationRequest The request object containing configuration details for the campaign search.
+	 * @return The response object containing the result of the campaign search.
+	 */
+    public Object performCampaignSearch(PlanConfigurationRequest planConfigurationRequest) {
+		CampaignSearchRequest campaignRequest = buildCampaignRequestForSearch(planConfigurationRequest);
+		return serviceRequestRepository.fetchResult(new StringBuilder(config.getProjectFactoryHostEndPoint()+config.getCampaignIntegrationSearchEndPoint()),
+				campaignRequest);
+	}
path: health-services/resource-generator/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java
user: login: Priyanka-eGov
body: done
created_at: 2025-04-03T06:05:47Z
author_association: COLLABORATOR
diff_hunk: @@ -31,6 +31,20 @@
 		this.mapper = mapper;
 	}
 
+	/**
+	 * Performs a campaign search based on the provided plan configuration request.
+	 * This method builds a campaign search request using the integration utility,
+	 * fetches the search result from the service request repository, and returns it.
+	 *
+	 * @param planConfigurationRequest The request object containing configuration details for the campaign search.
+	 * @return The response object containing the result of the campaign search.
+	 */
+    public Object performCampaignSearch(PlanConfigurationRequest planConfigurationRequest) {
+		CampaignSearchRequest campaignRequest = buildCampaignRequestForSearch(planConfigurationRequest);
+		return serviceRequestRepository.fetchResult(new StringBuilder(config.getProjectFactoryHostEndPoint()+config.getCampaignIntegrationSearchEndPoint()),
+				campaignRequest);
+	}
path: health-services/resource-generator/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java
user: login: coderabbitai[bot]
body: <details>
<summary>🧩 Analysis chain</summary>

@Priyanka-eGov Thank you for implementing the suggested changes. I'll verify if the exception handling has been added to the `performCampaignSearch` method as recommended.

---

🏁 Script executed:
```
#!/bin/bash
# Check if the performCampaignSearch method in CampaignIntegrationUtil now has exception handling
grep -A 20 "public Object performCampaignSearch" health-services/resource-generator/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java
```

Length of output: 1363

---

@Priyanka-eGov I noticed that the exception handling doesn't appear to be implemented in the `performCampaignSearch` method yet. Let me check if there are any pending changes to this file.

---

🏁 Script executed:
```
#!/bin/bash
# Let's check if the changes have been committed to the branch but not showing up in our initial query
git diff health-services/resource-generator/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java
```

Length of output: 112

---

@Priyanka-eGov I'd like to check the complete implementation to make sure we're on the same page regarding the exception handling changes.

---

🏁 Script executed:
```
#!/bin/bash
# Let's check the content of the current file to see the implementation of performCampaignSearch
cat health-services/resource-generator/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java
```

Length of output: 9076

---



</details>

@Priyanka-eGov I checked the code and it appears that the exception handling for the `performCampaignSearch` method hasn't been implemented yet. The method still has its original implementation without the try-catch block that was suggested in the previous comment.

For consistency with other methods in this class (like `updateResourcesInProjectFactory`), the suggestion was to add error handling like this:

```java
public Object performCampaignSearch(PlanConfigurationRequest planConfigurationRequest) {
    try {
        CampaignSearchRequest campaignRequest = buildCampaignRequestForSearch(planConfigurationRequest);
        return serviceRequestRepository.fetchResult(
            new StringBuilder(config.getProjectFactoryHostEndPoint() + config.getCampaignIntegrationSearchEndPoint()),
            campaignRequest
        );
    } catch (Exception e) {
        log.error("Error while fetching campaign details: " + planConfigurationRequest.getPlanConfiguration().getId(), e);
        throw new CustomException("ERROR_FETCHING_CAMPAIGN_DETAILS", e.toString());
    }
}
```

Would you like me to help with this implementation?

---

<details>
<summary>🧬 Code Definitions Used</summary>

### Relevant Code Snippets for `CampaignIntegrationUtil.java`

#### 1. `health-services/plan-service/src/main/java/digit/util/CampaignUtil.java`
```java
/**
 * Fetches a list of MixedStrategyOperationLogic objects from MDMS based on the provided planConfigurationRequest.
 *
 * @param request The PlanConfigurationRequest containing the plan configuration and request info.
 * @return A list of MixedStrategyOperationLogic objects fetched from MDMS.
 */
public List<MixedStrategyOperationLogic> fetchMixedStrategyOperationLogicFromMDMS(PlanConfigurationRequest request) {
    // Implementation details...
}
```
- **Filename**: `CampaignUtil.java`
- **Line Numbers**: 20-128

#### 2. `health-services/resource-generator/src/main/java/org/egov/processor/util/BoundaryUtil.java`
```java
/**
 * Searches for boundary relationships based on the given tenant ID and hierarchy type.
 *
 * @param tenantId                 The tenant ID for which the boundary search is performed.
 * @param hierarchyType            The hierarchy type of the boundary.
 * @param planConfigurationRequest The request object containing request info.
 */
public BoundarySearchResponse search(String tenantId, String hierarchyType, PlanConfigurationRequest planConfigurationRequest) {
    // Implementation details...
}
```
- **Filename**: `BoundaryUtil.java`
- **Line Numbers**: 17-66

#### 3. `health-services/resource-generator/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java`
```java
/**
 * Searches for plan configurations based on the given search request.
 *
 * @param planConfigurationSearchRequest The request object containing search criteria.
 * @return A list of planConfiguration objects that match the search criteria.
 */
public List<PlanConfiguration> search(PlanConfigurationSearchRequest planConfigurationSearchRequest) {
    // Implementation details...
}
```
- **Filename**: `PlanConfigurationUtil.java`
- **Line Numbers**: 20-128

#### 4. `health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmRecipientIdValidator.java`
```java
/**
 * Validates the recipient IDs in the ReferralBulkRequest.
 *
 * @param request The bulk request containing Referral entities.
 * @return A map containing Referral entities and their associated error details.
 */
@Override
public Map<Referral, List<Error>> validate(ReferralBulkRequest request) {
    // Implementation details...
}
```
- **Filename**: `RmRecipientIdValidator.java`
- **Line Numbers**: 33-107

#### 5. `health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmProjectBeneficiaryIdValidator.java`
```java
/**
 * Validates the project beneficiary IDs in the ReferralBulkRequest.
 *
 * @param request The bulk request containing Referral entities.
 * @return A map containing Referral entities and their associated error details.
 */
@Override
public Map<Referral, List<Error>> validate(ReferralBulkRequest request) {
    // Implementation details...
}
```
- **Filename**: `RmProjectBeneficiaryIdValidator.java`
- **Line Numbers**: 33-110

#### 6. `health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectBeneficiaryIdValidator.java`
```java
/**
 * Validates the project beneficiary IDs in the SideEffectBulkRequest.
 *
 * @param request The bulk request containing SideEffect entities.
 * @return A map containing SideEffect entities and their associated error details.
 */
@Override
public Map<SideEffect, List<Error>> validate(SideEffectBulkRequest request) {
    // Implementation details...
}
```
- **Filename**: `SeProjectBeneficiaryIdValidator.java`
- **Line Numbers**: 33-111

### Summary
The snippets provided above are relevant to understanding the `CampaignIntegrationUtil.java` file, particularly in the context of validating and processing campaign-related data, as well as handling requests and responses related to plan configurations and boundaries.

### Relevant Code Snippets

#### From `health-services/resource-generator/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java`

1. **Method: `performCampaignSearch`**
   - **Description**: Performs a campaign search based on the provided plan configuration request.
   - **Parameters**: 
     - `PlanConfigurationRequest planConfigurationRequest`: The request object containing configuration details for the campaign search.
   - **Return**: The response object containing the result of the campaign search.
   - **Line Numbers**: 35-41
   ```java
   public Object performCampaignSearch(PlanConfigurationRequest planConfigurationRequest) {
       CampaignSearchRequest campaignRequest = buildCampaignRequestForSearch(planConfigurationRequest);
       return serviceRequestRepository.fetchResult(new StringBuilder(config.getProjectFactoryHostEndPoint()+config.getCampaignIntegrationSearchEndPoint()),
               campaignRequest);
   }
   ```

2. **Method: `updateResourcesInProjectFactory`**
   - **Description**: Updates resources in the Project Factory by calling an external API with the given plan configuration request and file store ID.
   - **Parameters**: 
     - `PlanConfigurationRequest planConfigurationRequest`: The plan configuration request details.
     - `String fileStoreId`: The file store ID to update.
   - **Throws**: `CustomException` if the API call fails.
   - **Line Numbers**: 43-56
   ```java
   public void updateResourcesInProjectFactory(PlanConfigurationRequest planConfigurationRequest, String fileStoreId) {
       try {
           serviceRequestRepository.fetchResult(
                   new StringBuilder(config.getProjectFactoryHostEndPoint() + config.getCampaignIntegrationFetchFromMicroplanEndPoint()),
                   buildMicroplanDetailsForUpdate(planConfigurationRequest, fileStoreId));
           log.debug("Updated resources file into project factory - " + fileStoreId);
       } catch (Exception e) {
           log.error(ERROR_WHILE_CALLING_MICROPLAN_API + planConfigurationRequest.getPlanConfiguration().getId(), e);
           throw new CustomException(ERROR_WHILE_CALLING_MICROPLAN_API, e.toString());
       }
   }
   ```

3. **Method: `createProjectFactoryDataCall`**
   - **Description**: Sends a data creation request to the Project Factory service using the provided plan and campaign details.
   - **Parameters**: 
     - `PlanConfigurationRequest planConfigurationRequest`: The plan configuration request containing campaign data.
     - `CampaignResponse campaignResponse`: The response with additional campaign information.
   - **Throws**: `CustomException` if the data creation call fails.
   - **Line Numbers**: 66-78
   ```java
   public void createProjectFactoryDataCall(PlanConfigurationRequest planConfigurationRequest, CampaignResponse campaignResponse) {
       try {
           serviceRequestRepository.fetchResult(
                   new StringBuilder(config.getProjectFactoryHostEndPoint() + config.getCampaignIntegrationDataCreateEndPoint()),
                   buildResourceDetailsObjectForFacilityCreate(planConfigurationRequest, campaignResponse));
           log.info("Campaign Data create successful.");
       } catch (Exception e) {
           log.error(ERROR_WHILE_DATA_CREATE_CALL
                   + planConfigurationRequest.getPlanConfiguration().getCampaignId(), e);
           throw new CustomException("Failed to update campaign details in CampaignIntegration class within method updateCampaignDetails.", e.toString());
       }
   }
   ```

4. **Method: `buildCampaignRequestForSearch`**
   - **Description**: Builds a campaign search request based on the provided plan configuration request.
   - **Parameters**: 
     - `PlanConfigurationRequest planConfigurationRequest`: The plan configuration request containing necessary information for building the search request.
   - **Return**: The campaign search request object built for searching campaigns.
   - **Line Numbers**: 112-120
   ```java
   public CampaignSearchRequest buildCampaignRequestForSearch(PlanConfigurationRequest planConfigurationRequest) {
       PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration();
       List<String> id = new ArrayList<String>();
       id.add(planConfig.getCampaignId());
       return CampaignSearchRequest.builder().requestInfo(planConfigurationRequest.getRequestInfo())
               .campaignDetails(CampaignDetails.builder().ids(id).tenantId(planConfig.getTenantId()).build()).build();
   }
   ```

5. **Method: `parseCampaignResponse`**
   - **Description**: Parses an object representing campaign response into a CampaignResponse object.
   - **Parameters**: 
     - `Object campaignResponse`: The object representing campaign response to be parsed.
   - **Return**: CampaignResponse object parsed from the campaignResponse.
   - **Line Numbers**: 126-130
   ```java
   public CampaignResponse parseCampaignResponse(Object campaignResponse) {
       return mapper.convertValue(campaignResponse, CampaignResponse.class);
   }
   ```

6. **Method: `createAdditionalDetailsForFacilityCreate`**
   - **Description**: Creates a JSON node containing additional details for facility creation.
   - **Parameters**: 
     - `String source`: The source from which the facility creation request originates.
     - `String microplanId`: The microplan ID associated with the facility.
   - **Return**: A JSON node representing the additional details.
   - **Line Numbers**: 132-142
   ```java
   public JsonNode createAdditionalDetailsForFacilityCreate(String source, String microplanId) {
       try {
           Map<String, String> additionalDetailsMap = new HashMap<>();
           additionalDetailsMap.put(SOURCE_KEY, source);
           additionalDetailsMap.put(MICROPLAN_ID_KEY, microplanId);
           return mapper.valueToTree(additionalDetailsMap);
       } catch (Exception e) {
           throw new CustomException(UNABLE_TO_CREATE_ADDITIONAL_DETAILS_CODE, UNABLE_TO_CREATE_ADDITIONAL_DETAILS_MESSAGE);
       }
   }
   ```

#### From `health-services/resource-generator/src/main/java/org/egov/processor/config/ErrorConstants.java`

1. **Error Constants**
   - **Description**: Contains various error constants used throughout the application.
   - **Line Numbers**: 5-71
   ```java
   public static final String FILE_NOT_FOUND_CODE = "FILE_NOT_FOUND";
   public static final String FILE_NOT_FOUND_MESSAGE = "The file with ID %s was not found in the tenant %s";
   public static final String ERROR_WHILE_CALLING_MICROPLAN_API = "Unexpected error while calling fetch from Microplan API for plan config Id: ";
   public static final String ERROR_WHILE_DATA_CREATE_CALL = "Exception occurred while creating data for campaign - ";
   ```

#### From `health-services/resource-generator/src/main/java/org/egov/processor/util/FilestoreUtil.java`

1. **Method: `getFileByteArray`**
   - **Description**: Retrieves a file from the file store service based on the tenant ID and file store ID.
   - **Parameters**: 
     - `String tenantId`: The ID of the tenant.
     - `String fileStoreId`: The ID of the file in the file store.
   - **Return**: The file content as a byte array.
   - **Line Numbers**: 34-45
   ```java
   public byte[] getFileByteArray(String tenantId, String fileStoreId) {
       String fileStoreServiceLink = getFileStoreServiceLink(tenantId, fileStoreId);
       byte[] responseInByteArray;
       Object response;
       try {
           response = serviceRequestRepository.fetchResultWithGET(new StringBuilder(fileStoreServiceLink));
           responseInByteArray = (byte[]) response;
       } catch (Exception ex) {
           log.error("File store id response error!!", ex);
           throw new CustomException("FILESTORE_EXCEPTION", "File Store response can not parsed!!!");
       }
       return responseInByteArray;
   }
   ```

2. **Method: `uploadFile`**
   - **Description**: Uploads a file to the file store service.
   - **Parameters**: 
     - `File file`: The file to upload.
     - `String tenantId`: The ID of the tenant.
   - **Return**: The file store ID of the uploaded file.
   - **Line Numbers**: 48-60
   ```java
   public String uploadFile(File file, String tenantId) {
       byte[] fileContent = readFileContent(file);
       MultipartFile multipartFile = createMultipartFile(file, fileContent);
       String url = config.getFileStoreHost() + config.getFileStoreUploadEndpoint();
       HttpHeaders headers = createHttpHeaders(multipartFile.getName());
       MultiValueMap<String, Object> body = createHttpBody(multipartFile, tenantId);
       HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
       ResponseEntity<String> responseEntity = serviceRequestRepository.sendHttpRequest(url, requestEntity);
       return fetchFilestoreIdFromResponse(responseEntity);
   }
   ```

3. **Method: `fetchFilestoreIdFromResponse`**
   - **Description**: Extracts the file store ID from the response entity of the file store service.
   - **Parameters**: 
     - `ResponseEntity<String> responseEntity`: The response entity from the file store service.
   - **Return**: The file store ID of the uploaded file.
   - **Line Numbers**: 165-176
   ```java
   public String fetchFilestoreIdFromResponse(ResponseEntity<String> responseEntity) {
       ObjectMapper objectMapper = new ObjectMapper();
       JsonNode rootNode;
       try {
           rootNode = objectMapper.readTree(responseEntity.getBody());
       } catch (JsonProcessingException e) {
           log.error(e.getMessage());
           throw new CustomException("FILESTORE_EXCEPTION", "File Store response can not parsed!!!");
       }
       String fileStoreId = rootNode.get(FILES).get(0).get(FILESTORE_ID).asText();
       return fileStoreId;
   }
   ```

### Summary
The relevant snippets from the provided files focus on the `CampaignIntegrationUtil` class, which handles various operations related to campaign management, including searching for campaigns, updating resources, and creating project factory data. Additionally, error constants and utility methods for file handling are included, which may be pertinent to the operations performed in `CampaignIntegrationUtil`.

### Relevant Code Snippets for `CampaignIntegrationUtil.java`

#### 1. `PlanQueryBuilder.java`
- **File:** `health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanQueryBuilder.java`
- **Line Range:** 12-220
```java
@Component
public class PlanQueryBuilder {
    // ... other code ...

    /**
     * Constructs the status count query to get the count of plans based on their current status for the given search criteria
     *
     * @param searchCriteria   The criteria used for filtering Plans.
     * @param preparedStmtList A list to store prepared statement parameters.
     * @return A SQL query string to get the status count of Plans for a given search criteria.
     */
    public String getPlanStatusCountQuery(PlanSearchCriteria searchCriteria, List<Object> preparedStmtList) {
        StringBuilder builder = new StringBuilder();
        // ... query building logic ...
        return PLAN_STATUS_COUNT_QUERY.replace("{INTERNAL_QUERY}", builder);
    }

    // ... other code ...
}
```

#### 2. `PlanUtil.java`
- **File:** `health-services/resource-generator/src/main/java/org/egov/processor/util/PlanUtil.java`
- **Line Range:** 32-322
```java
@Component
@Slf4j
public class PlanUtil {
    // ... other code ...

    /**
     * Creates a plan configuration request, builds a plan request from it, and pushes it to the messaging system for further processing.
     * 
     * @param planConfigurationRequest The plan configuration request.
     * @param feature The feature JSON node.
     * @param resultMap The result map.
     * @param boundaryCodeToCensusAdditionalDetails A Map of boundary code to censusAdditionalDetails for that boundary code.
     */
    public void create(PlanConfigurationRequest planConfigurationRequest, JsonNode feature,
            Map<String, BigDecimal> resultMap, Map<String, Object> boundaryCodeToCensusAdditionalDetails) {
        // ... implementation ...
    }

    // ... other code ...
}
```

#### 3. `PlanFacilityValidator.java`
- **File:** `health-services/plan-service/src/main/java/digit/service/validator/PlanFacilityValidator.java`
- **Line Range:** 28-286
```java
@Component
@Slf4j
public class PlanFacilityValidator {
    // ... other code ...

    /**
     * This method validates the Plan Facility Create request.
     * It performs multiple validations such as plan configuration, facility existence,
     * and campaign-related validations.
     *
     * @param planFacilityRequest The plan facility request to be validated.
     */
    public void validatePlanFacilityCreate(PlanFacilityRequest planFacilityRequest) {
        // ... validation logic ...
    }

    // ... other code ...
}
```

#### 4. `CommonUtil.java`
- **File:** `health-services/plan-service/src/main/java/digit/util/CommonUtil.java`
- **Line Range:** 28-322
```java
@Component
@Slf4j
public class CommonUtil {
    // ... other code ...

    /**
     * Validates the user information within the provided PlanConfigurationRequest.
     *
     * @param requestInfo the request info containing the user information to be validated
     * @throws CustomException if the user information is missing in the request
     */
    public void validateUserInfo(RequestInfo requestInfo) {
        if (ObjectUtils.isEmpty(requestInfo.getUserInfo())) {
            log.error(USERINFO_MISSING_MESSAGE);
            throw new CustomException(USERINFO_MISSING_CODE, USERINFO_MISSING_MESSAGE);
        }
    }

    // ... other code ...
}
```

#### 5. `PlanConfigurationValidator.java`
- **File:** `health-services/plan-service/src/main/java/digit/service/validator/PlanConfigurationValidator.java`
- **Line Range:** 28-575
```java
@Component
@Slf4j
public class PlanConfigurationValidator {
    // ... other code ...

    /**
     * Validates the create request for plan configuration, including assumptions against MDMS data.
     *
     * @param request The create request for plan configuration.
     */
    public void validateCreate(PlanConfigurationRequest request) {
        // ... validation logic ...
    }

    // ... other code ...
}
```

#### 6. `PlanValidator.java`
- **File:** `health-services/plan-service/src/main/java/digit/service/PlanValidator.java`
- **Line Range:** 27-670
```java
@Component
public class PlanValidator {
    // ... other code ...

    /**
     * This method performs business validations on plan create requests
     *
     * @param request
     */
    public void validatePlanCreate(PlanRequest request) {
        // ... validation logic ...
    }

    // ... other code ...
}
```

These snippets provide context on how the `CampaignIntegrationUtil` interacts with other components, particularly in terms of validating requests and handling campaign-related data.

### Relevant Code Snippets

#### From `health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java`

**Line 42-898: `ExcelParser` Class**
```java
@Slf4j
@Service
public class ExcelParser implements FileParser {
    private CampaignIntegrationUtil campaignIntegrationUtil;

    public ExcelParser(ObjectMapper objectMapper, ParsingUtil parsingUtil, FilestoreUtil filestoreUtil,
                       CalculationUtil calculationUtil, PlanUtil planUtil, CampaignIntegrationUtil campaignIntegrationUtil,
                       Configuration config, MdmsUtil mdmsUtil, BoundaryUtil boundaryUtil, LocaleUtil localeUtil, CensusUtil censusUtil, EnrichmentUtil enrichmentUtil, PlanConfigurationUtil planConfigurationUtil, OutputEstimationGenerationUtil outputEstimationGenerationUtil, MixedStrategyUtil mixedStrategyUtil, PlanFacilityUtil planFacilityUtil) {
        this.campaignIntegrationUtil = campaignIntegrationUtil;
    }

    /**
     * Parses file data, extracts information from the file, and processes it.
     *
     * @param planConfigurationRequest The plan configuration request containing
     *                                 necessary information for parsing the file.
     * @param fileStoreId              The ID of the file in the file store.
     * @param campaignResponse         The response object to be updated with parsed
     *                                 data.
     * @return The parsed and processed data.
     */
    @Override
    public Object parseFileData(PlanConfigurationRequest planConfigurationRequest, String fileStoreId,
                                Object campaignResponse) {
        // Implementation details...
        campaignIntegrationUtil.updateResourcesInProjectFactory(planConfigurationRequest, uploadedFileStoreId);
        // Further processing...
    }

    /**
     * Uploads a converted file and integrates campaign details if configured to do so.
     *
     * @param planConfigurationRequest The request containing configuration details including tenant ID.
     * @param workbook                 The workbook containing data to be uploaded and integrated.
     * @param filestoreId              The ID of the file in the file store.
     */
    private void uploadFileAndIntegrateCampaign(PlanConfigurationRequest planConfigurationRequest, Workbook workbook, String filestoreId) {
        // Implementation details...
        campaignIntegrationUtil.updateResourcesInProjectFactory(planConfigurationRequest, uploadedFileStoreId);
        // Further processing...
    }
}
```

#### From `health-services/libraries/health-services-common/src/main/java/org/egov/common/utils/CommonUtils.java`

**Line 46-1159: `CommonUtils` Class**
```java
@Slf4j
public class CommonUtils {
    /**
     * Retrieves audit details for creating an entity.
     * This method generates audit details including creation and last modified timestamps.
     *
     * @param requestInfo The request information containing user details.
     * @return The audit details for create operation.
     */
    public static AuditDetails getAuditDetailsForCreate(RequestInfo requestInfo) {
        log.info("Creating audit details for create api");
        Long time = System.currentTimeMillis();
        return AuditDetails.builder()
                .createdBy(requestInfo.getUserInfo().getUuid())
                .createdTime(time)
                .lastModifiedBy(requestInfo.getUserInfo().getUuid())
                .lastModifiedTime(time)
                .build();
    }

    /**
     * Get auditDetails having only the lastModifiedBy and lastModifiedTime fields set.
     *
     * @param existingAuditDetails is the audit details coming from request.
     * @param modifiedByUuid is the uuid of the user performing this update.
     * @return auditDetails
     */
    public static AuditDetails getAuditDetailsForUpdate(AuditDetails existingAuditDetails, String modifiedByUuid) {
        log.info("Creating audit details for update/delete api");
        if (existingAuditDetails == null) {
            return AuditDetails.builder()
                    .lastModifiedBy(modifiedByUuid)
                    .lastModifiedTime(System.currentTimeMillis()).build();
        } else {
            existingAuditDetails.setLastModifiedBy(modifiedByUuid);
            existingAuditDetails.setLastModifiedTime(System.currentTimeMillis());
            return existingAuditDetails;
        }
    }
}
```

### Summary of Relevant Snippets
- The `ExcelParser` class contains methods that utilize `CampaignIntegrationUtil` to update resources in the project factory based on the parsed Excel file data.
- The `CommonUtils` class provides utility methods for creating and updating audit details, which may be relevant for tracking changes made during the campaign integration process.

</details>



<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-04-03T06:09:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -31,6 +31,20 @@ public CampaignIntegrationUtil(ServiceRequestRepository serviceRequestRepository
 		this.mapper = mapper;
 	}
 
+	/**
+	 * Performs a campaign search based on the provided plan configuration request.
+	 * This method builds a campaign search request using the integration utility,
+	 * fetches the search result from the service request repository, and returns it.
+	 *
+	 * @param planConfigurationRequest The request object containing configuration details for the campaign search.
+	 * @return The response object containing the result of the campaign search.
+	 */
+    public Object performCampaignSearch(PlanConfigurationRequest planConfigurationRequest) {
+		CampaignSearchRequest campaignRequest = buildCampaignRequestForSearch(planConfigurationRequest);
+		return serviceRequestRepository.fetchResult(new StringBuilder(config.getProjectFactoryHostEndPoint()+config.getCampaignIntegrationSearchEndPoint()),
+				campaignRequest);
+	}
path: health-services/resource-generator/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java
user: login: Priyanka-eGov
body: Will take care of this in ticket - https://digit-discuss.atlassian.net/browse/HCMPRE-2589
created_at: 2025-04-03T06:23:26Z
author_association: COLLABORATOR
diff_hunk: @@ -31,6 +31,20 @@ public CampaignIntegrationUtil(ServiceRequestRepository serviceRequestRepository
 		this.mapper = mapper;
 	}
 
+	/**
+	 * Performs a campaign search based on the provided plan configuration request.
+	 * This method builds a campaign search request using the integration utility,
+	 * fetches the search result from the service request repository, and returns it.
+	 *
+	 * @param planConfigurationRequest The request object containing configuration details for the campaign search.
+	 * @return The response object containing the result of the campaign search.
+	 */
+    public Object performCampaignSearch(PlanConfigurationRequest planConfigurationRequest) {
+		CampaignSearchRequest campaignRequest = buildCampaignRequestForSearch(planConfigurationRequest);
+		return serviceRequestRepository.fetchResult(new StringBuilder(config.getProjectFactoryHostEndPoint()+config.getCampaignIntegrationSearchEndPoint()),
+				campaignRequest);
+	}
path: health-services/resource-generator/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java
user: login: coderabbitai[bot]
body: @Priyanka-eGov Sounds good! Thanks for creating a separate ticket to address this improvement. I appreciate your organized approach to tracking these enhancements.

---

<details>
<summary>🧬 Code Definitions Used</summary>

### Relevant Code Snippets for `CampaignIntegrationUtil.java`

#### 1. `health-services/plan-service/src/main/java/digit/util/CampaignUtil.java`
```java
/**
 * Fetches a list of MixedStrategyOperationLogic objects from MDMS based on the provided planConfigurationRequest.
 *
 * @param request The PlanConfigurationRequest containing the plan configuration and request info.
 * @return A list of MixedStrategyOperationLogic objects fetched from MDMS.
 */
public List<MixedStrategyOperationLogic> fetchMixedStrategyOperationLogicFromMDMS(PlanConfigurationRequest request) {
    // Implementation details...
}
```
- **Filename**: `CampaignUtil.java`
- **Line Numbers**: 20-92

#### 2. `health-services/resource-generator/src/main/java/org/egov/processor/util/BoundaryUtil.java`
```java
/**
 * Searches for boundary relationships based on the given tenant ID and hierarchy type.
 *
 * @param tenantId                 The tenant ID for which the boundary search is performed.
 * @param hierarchyType            The hierarchy type of the boundary.
 * @param planConfigurationRequest The request object containing request info.
 */
public BoundarySearchResponse search(String tenantId, String hierarchyType, PlanConfigurationRequest planConfigurationRequest) {
    // Implementation details...
}
```
- **Filename**: `BoundaryUtil.java`
- **Line Numbers**: 17-66

#### 3. `health-services/resource-generator/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java`
```java
/**
 * Searches for plan configurations based on the given search request.
 *
 * @param planConfigurationSearchRequest The request object containing search criteria.
 * @return A list of planConfiguration objects that match the search criteria.
 */
public List<PlanConfiguration> search(PlanConfigurationSearchRequest planConfigurationSearchRequest) {
    // Implementation details...
}
```
- **Filename**: `PlanConfigurationUtil.java`
- **Line Numbers**: 20-128

#### 4. `health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmRecipientIdValidator.java`
```java
/**
 * Validates the recipient ID for referrals.
 *
 * @param request The bulk request containing Referral entities.
 * @return A map containing Referral entities and their associated error details.
 */
@Override
public Map<Referral, List<Error>> validate(ReferralBulkRequest request) {
    // Implementation details...
}
```
- **Filename**: `RmRecipientIdValidator.java`
- **Line Numbers**: 33-107

#### 5. `health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrProjectIdValidator.java`
```java
/**
 * Validates whether projects exist in the database or not using project IDs for HFReferral objects.
 *
 * @param request The HFReferralBulkRequest containing a list of HFReferral entities
 * @return A Map containing HFReferral entities as keys and lists of errors as values
 */
@Override
public Map<HFReferral, List<Error>> validate(HFReferralBulkRequest request) {
    // Implementation details...
}
```
- **Filename**: `HfrProjectIdValidator.java`
- **Line Numbers**: 33-131

#### 6. `health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectBeneficiaryIdValidator.java`
```java
/**
 * Validates the project beneficiary ID for side effects.
 *
 * @param request The SideEffectBulkRequest containing SideEffect entities.
 * @return A map containing SideEffect entities and their associated error details.
 */
@Override
public Map<SideEffect, List<Error>> validate(SideEffectBulkRequest request) {
    // Implementation details...
}
```
- **Filename**: `SeProjectBeneficiaryIdValidator.java`
- **Line Numbers**: 33-111

#### 7. `health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java`
```java
/**
 * Validates whether the project task ID and client reference ID exist or not in the database for SideEffect objects.
 *
 * @param request The SideEffectBulkRequest containing SideEffect entities.
 * @return A map containing SideEffect entities and their associated error details.
 */
@Override
public Map<SideEffect, List<Error>> validate(SideEffectBulkRequest request) {
    // Implementation details...
}
```
- **Filename**: `SeProjectTaskIdValidator.java`
- **Line Numbers**: 33-111

#### 8. `health-services/project/src/main/java/org/egov/project/validator/task/PtProductVariantIdValidator.java`
```java
/**
 * Validates the product variant IDs in the TaskBulkRequest.
 *
 * @param request The TaskBulkRequest containing Task entities.
 * @return A map containing Task entities and their associated error details.
 */
@Override
public Map<Task, List<Error>> validate(TaskBulkRequest request) {
    // Implementation details...
}
```
- **Filename**: `PtProductVariantIdValidator.java`
- **Line Numbers**: 39-114

### Summary
The snippets provided above are relevant to the `CampaignIntegrationUtil.java` file as they involve validation and fetching of various entities and configurations that may interact with the campaign integration process. Each snippet includes a brief description of its purpose and the relevant file and line numbers for easy reference.

### Relevant Code Snippets for `CampaignIntegrationUtil.java`

#### 1. `ErrorConstants.java` (Lines 5-71)
```java
@Component
public class ErrorConstants {
    public static final String ERROR_WHILE_CALLING_MICROPLAN_API =
            "Unexpected error while calling fetch from Microplan API for plan config Id: ";
    public static final String ERROR_WHILE_DATA_CREATE_CALL = "Exception occurred while creating data for campaign - ";
    public static final String FILE_NOT_FOUND_CODE = "FILE_NOT_FOUND";
    public static final String FILE_NOT_FOUND_TEMPLATE_IDENTIFIER_MESSAGE = "No file with the specified templateIdentifier found - ";
    // Other error constants...
}
```
- **Description**: This snippet defines various error constants used throughout the application, including those related to API calls and file handling.

#### 2. `ServiceConstants.java` (Lines 7-121)
```java
@Component
public class ServiceConstants {
    public static final String FILE_TEMPLATE_IDENTIFIER_FACILITY = "Facilities";
    public static final String TYPE_FACILITY = "facility";
    public static final String ACTION_CREATE = "create";
    public static final String SOURCE_KEY = "source";
    public static final String MICROPLAN_SOURCE_KEY = "microplan";
    public static final String MICROPLAN_ID_KEY = "microplanId";
    // Other service constants...
}
```
- **Description**: This snippet contains constants related to service operations, including identifiers for file templates and action types.

#### 3. `CensusUtil.java` (Lines 22-228)
```java
@Component
public class CensusUtil {
    public void create(PlanConfigurationRequest planConfigurationRequest, JsonNode feature, Map<String, String> mappedValues, String heirarchyType) {
        CensusRequest censusRequest = buildCensusRequest(planConfigurationRequest, feature, mappedValues, heirarchyType);
        try {
            producer.push(config.getResourceCensusCreateTopic(), censusRequest);
        } catch (Exception e) {
            log.error(ERROR_WHILE_PUSHING_TO_PLAN_SERVICE_FOR_LOCALITY + censusRequest.getCensus().getBoundaryCode(), e);
        }
    }

    private CensusRequest buildCensusRequest(PlanConfigurationRequest planConfigurationRequest, JsonNode feature, Map<String, String> mappedValues, String hierarchyType) {
        // Build and return a CensusRequest object...
    }
}
```
- **Description**: This snippet shows methods for creating and building a `CensusRequest`, which is relevant for handling census data related to campaigns.

#### 4. `PlanConfigurationRequest.java` (Assumed structure)
```java
public class PlanConfigurationRequest {
    private PlanConfiguration planConfiguration;
    private RequestInfo requestInfo;

    // Getters and Setters...
}
```
- **Description**: This class represents the request structure for plan configurations, which includes the plan configuration details and request information.

#### 5. `PlanConfiguration.java` (Assumed structure)
```java
public class PlanConfiguration {
    private String id;
    private String tenantId;
    private String campaignId;
    private List<File> files;
    private List<Assumption> assumptions;
    private List<Operation> operations;
    private List<ResourceMapping> resourceMapping;
    private AuditDetails auditDetails;

    // Getters and Setters...
}
```
- **Description**: This class represents the plan configuration details, including associated files, assumptions, operations, and audit details.

#### 6. `ServiceRequestRepository.java` (Assumed structure)
```java
public class ServiceRequestRepository {
    public Object fetchResult(StringBuilder uri, Object request) {
        // Implementation for fetching results from a service...
    }
}
```
- **Description**: This repository class is responsible for making service requests and fetching results, which is crucial for the operations in `CampaignIntegrationUtil`.

#### 7. `PlanConfigurationRequest.java` (Assumed structure)
```java
public class PlanConfigurationRequest {
    private PlanConfiguration planConfiguration;
    private RequestInfo requestInfo;

    // Getters and Setters...
}
```
- **Description**: This class represents the request structure for plan configurations, which includes the plan configuration details and request information.

#### 8. `PlanConfiguration.java` (Assumed structure)
```java
public class PlanConfiguration {
    private String id;
    private String tenantId;
    private String campaignId;
    private List<File> files;
    private List<Assumption> assumptions;
    private List<Operation> operations;
    private List<ResourceMapping> resourceMapping;
    private AuditDetails auditDetails;

    // Getters and Setters...
}
```
- **Description**: This class represents the plan configuration details, including associated files, assumptions, operations, and audit details.

#### 9. `ServiceRequestRepository.java` (Assumed structure)
```java
public class ServiceRequestRepository {
    public Object fetchResult(StringBuilder uri, Object request) {
        // Implementation for fetching results from a service...
    }
}
```
- **Description**: This repository class is responsible for making service requests and fetching results, which is crucial for the operations in `CampaignIntegrationUtil`.

### Summary
The relevant snippets provide context on error handling, service constants, and the structure of request and response objects used in the `CampaignIntegrationUtil` class. These components are essential for understanding how the utility interacts with other parts of the application, particularly in managing campaign-related operations and handling service requests.

### Relevant Code Snippets

#### From `health-services/resource-generator/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java`

1. **Method: `performCampaignSearch`**
   - **Description**: Performs a campaign search based on the provided plan configuration request.
   - **Parameters**: 
     - `PlanConfigurationRequest planConfigurationRequest`: The request object containing configuration details for the campaign search.
   - **Return**: The response object containing the result of the campaign search.
   - **Line Numbers**: 36-42
   ```java
   public Object performCampaignSearch(PlanConfigurationRequest planConfigurationRequest) {
       CampaignSearchRequest campaignRequest = buildCampaignRequestForSearch(planConfigurationRequest);
       return serviceRequestRepository.fetchResult(new StringBuilder(config.getProjectFactoryHostEndPoint()+config.getCampaignIntegrationSearchEndPoint()),
               campaignRequest);
   }
   ```

2. **Method: `updateResourcesInProjectFactory`**
   - **Description**: Updates resources in the Project Factory by calling an external API with the given plan configuration request and file store ID.
   - **Parameters**: 
     - `PlanConfigurationRequest planConfigurationRequest`: The plan configuration request details.
     - `String fileStoreId`: The file store ID to update.
   - **Throws**: `CustomException` if the API call fails.
   - **Line Numbers**: 44-56
   ```java
   public void updateResourcesInProjectFactory(PlanConfigurationRequest planConfigurationRequest, String fileStoreId) {
       try {
           serviceRequestRepository.fetchResult(
                   new StringBuilder(config.getProjectFactoryHostEndPoint() + config.getCampaignIntegrationFetchFromMicroplanEndPoint()),
                   buildMicroplanDetailsForUpdate(planConfigurationRequest, fileStoreId));
           log.debug("Updated resources file into project factory - " + fileStoreId);
       } catch (Exception e) {
           log.error(ERROR_WHILE_CALLING_MICROPLAN_API + planConfigurationRequest.getPlanConfiguration().getId(), e);
           throw new CustomException(ERROR_WHILE_CALLING_MICROPLAN_API, e.toString());
       }
   }
   ```

3. **Method: `createProjectFactoryDataCall`**
   - **Description**: Sends a data creation request to the Project Factory service using the provided plan and campaign details.
   - **Parameters**: 
     - `PlanConfigurationRequest planConfigurationRequest`: The plan configuration request containing campaign data.
     - `CampaignResponse campaignResponse`: The response with additional campaign information.
   - **Throws**: `CustomException` if the data creation call fails.
   - **Line Numbers**: 66-78
   ```java
   public void createProjectFactoryDataCall(PlanConfigurationRequest planConfigurationRequest, CampaignResponse campaignResponse) {
       try {
           serviceRequestRepository.fetchResult(
                   new StringBuilder(config.getProjectFactoryHostEndPoint() + config.getCampaignIntegrationDataCreateEndPoint()),
                   buildResourceDetailsObjectForFacilityCreate(planConfigurationRequest, campaignResponse));
           log.info("Campaign Data create successful.");
       } catch (Exception e) {
           log.error(ERROR_WHILE_DATA_CREATE_CALL
                   + planConfigurationRequest.getPlanConfiguration().getCampaignId(), e);
           throw new CustomException("Failed to update campaign details in CampaignIntegration class within method updateCampaignDetails.", e.toString());
       }
   }
   ```

4. **Method: `buildCampaignRequestForSearch`**
   - **Description**: Builds a campaign search request based on the provided plan configuration request.
   - **Parameters**: 
     - `PlanConfigurationRequest planConfigurationRequest`: The plan configuration request containing necessary information for building the search request.
   - **Return**: The campaign search request object built for searching campaigns.
   - **Line Numbers**: 80-88
   ```java
   public CampaignSearchRequest buildCampaignRequestForSearch(PlanConfigurationRequest planConfigurationRequest) {
       PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration();
       List<String> id = new ArrayList<String>();
       id.add(planConfig.getCampaignId());
       return CampaignSearchRequest.builder().requestInfo(planConfigurationRequest.getRequestInfo())
               .campaignDetails(CampaignDetails.builder().ids(id).tenantId(planConfig.getTenantId()).build()).build();
   }
   ```

5. **Method: `parseCampaignResponse`**
   - **Description**: Parses an object representing campaign response into a CampaignResponse object.
   - **Parameters**: 
     - `Object campaignResponse`: The object representing campaign response to be parsed.
   - **Return**: CampaignResponse object parsed from the campaignResponse.
   - **Line Numbers**: 90-94
   ```java
   public CampaignResponse parseCampaignResponse(Object campaignResponse) {
       return mapper.convertValue(campaignResponse, CampaignResponse.class);
   }
   ```

#### From `health-services/plan-service/src/main/java/digit/service/validator/PlanConfigurationValidator.java`

6. **Method: `validateCreate`**
   - **Description**: Validates the create request for plan configuration, including assumptions against MDMS data.
   - **Parameters**: 
     - `PlanConfigurationRequest request`: The create request for plan configuration.
   - **Line Numbers**: 28-60
   ```java
   public void validateCreate(PlanConfigurationRequest request) {
       PlanConfiguration planConfiguration = request.getPlanConfiguration();
       String rootTenantId = centralInstanceUtil.getStateLevelTenant(planConfiguration.getTenantId());
       Object mdmsData = mdmsUtil.fetchMdmsData(request.getRequestInfo(), rootTenantId);
       CampaignResponse campaignResponse = campaignUtil.fetchCampaignData(request.getRequestInfo(), request.getPlanConfiguration().getCampaignId(), rootTenantId);
       // Validate if the plan configuration for the provided name and campaign id already exists
       validateDuplicateRecord(planConfiguration);
       // Validate if campaign id exists against project factory
       validateCampaignId(campaignResponse);
       // Validate that the assumption keys in the request are present in the MDMS data
       validateAssumptionKeyAgainstMDMS(request, mdmsData);
       // Validate that the assumption keys in the request are unique
       validateAssumptionUniqueness(planConfiguration);
       // Validate that the template identifiers in the request match those in the MDMS data
       validateTemplateIdentifierAgainstMDMS(request, mdmsData);
       // Validating operation's input and assumptionValue fields
       validateOperations(request, campaignResponse);
       // Validating plan config name against MDMS data
       validatePlanConfigName(request, mdmsData);
       // Validate the user information in the request
       commonUtil.validateUserInfo(request.getRequestInfo());
       // Validates the vehicle id from additional details object against the data from mdms v2
       validateVehicleIdsFromAdditionalDetailsAgainstMDMS(request, mdmsV2Data);
   }
   ```

7. **Method: `validateCampaignId`**
   - **Description**: Validates campaign ID from request against project factory.
   - **Parameters**: 
     - `CampaignResponse campaignResponse`: The campaign details response from project factory.
   - **Line Numbers**: 62-66
   ```java
   private void validateCampaignId(CampaignResponse campaignResponse) {
       if (CollectionUtils.isEmpty(campaignResponse.getCampaignDetails())) {
           throw new CustomException(NO_CAMPAIGN_DETAILS_FOUND_FOR_GIVEN_CAMPAIGN_ID_CODE, NO_CAMPAIGN_DETAILS_FOUND_FOR_GIVEN_CAMPAIGN_ID_MESSAGE);
       }
   }
   ```

8. **Method: `validateAssumptionKeyAgainstMDMS`**
   - **Description**: Validates the assumption keys against MDMS data.
   - **Parameters**: 
     - `PlanConfigurationRequest request`: The request containing the plan configuration and the MDMS data.
     - `Object mdmsData`: The MDMS data.
   - **Line Numbers**: 112-130
   ```java
   public void validateAssumptionKeyAgainstMDMS(PlanConfigurationRequest request, Object mdmsData) {
       PlanConfiguration planConfiguration = request.getPlanConfiguration();
       if (!CollectionUtils.isEmpty(planConfiguration.getAssumptions())) {
           Object additionalDetails = request.getPlanConfiguration().getAdditionalDetails();
           if (additionalDetails == null) {
               throw new CustomException(ADDITIONAL_DETAILS_MISSING_CODE, ADDITIONAL_DETAILS_MISSING_MESSAGE);
           }
           String jsonPathForAssumption = commonUtil.createJsonPathForAssumption(commonUtil.extractFieldsFromJsonObject(additionalDetails, JSON_FIELD_CAMPAIGN_TYPE, String.class),
                   commonUtil.extractFieldsFromJsonObject(additionalDetails, JSON_FIELD_DISTRIBUTION_PROCESS, String.class),
                   commonUtil.extractFieldsFromJsonObject(additionalDetails, JSON_FIELD_REGISTRATION_PROCESS, String.class),
                   commonUtil.extractFieldsFromJsonObject(additionalDetails, JSON_FIELD_RESOURCE_DISTRIBUTION_STRATEGY_CODE, String.class),
                   commonUtil.extractFieldsFromJsonObject(additionalDetails, JSON_FIELD_IS_REGISTRATION_AND_DISTRIBUTION_TOGETHER, String.class));
           List<Object> assumptionListFromMDMS = null;
           try {
               log.debug(jsonPathForAssumption);
               assumptionListFromMDMS = JsonPath.read(mdmsData, jsonPathForAssumption);
           } catch (Exception e) {
               log.error(e.getMessage());
               throw new CustomException(JSONPATH_ERROR_CODE, JSONPATH_ERROR_MESSAGE);
           }
           Set<Object> assumptionSetFromMDMS = new HashSet<>(assumptionListFromMDMS);
           planConfiguration.getAssumptions().forEach(assumption -> {
               if (assumption.getActive() && assumption.getSource() == Source.MDMS && !assumptionSetFromMDMS.contains(assumption.getKey())) {
                   log.error(ASSUMPTION_KEY_NOT_FOUND_IN_MDMS_MESSAGE + assumption.getKey());
                   throw new CustomException(ASSUMPTION_KEY_NOT_FOUND_IN_MDMS_CODE, ASSUMPTION_KEY_NOT_FOUND_IN_MDMS_MESSAGE + assumption.getKey() + " at JSONPath: " + jsonPathForAssumption);
               }
           });
       }
   }
   ```

#### From `health-services/plan-service/src/main/java/digit/service/PlanValidator.java`

9. **Method: `validatePlanCreate`**
   - **Description**: This method performs business validations on plan create requests.
   - **Parameters**: 
     - `PlanRequest request`: The request containing plan details to validate.
   - **Line Numbers**: 28-60
   ```java
   public void validatePlanCreate(PlanRequest request) {
       String rootTenantId = centralInstanceUtil.getStateLevelTenant(request.getPlan().getTenantId());
       Object mdmsData = mdmsUtil.fetchMdmsData(request.getRequestInfo(), rootTenantId);
       CampaignResponse campaignResponse = campaignUtil.fetchCampaignData(request.getRequestInfo(), request.getPlan().getCampaignId(), rootTenantId);
       BoundarySearchResponse boundarySearchResponse = boundaryUtil.fetchBoundaryData(request.getRequestInfo(), request.getPlan().getLocality(), request.getPlan().getTenantId(), campaignResponse.getCampaignDetails().get(0).getHierarchyType(), Boolean.TRUE, Boolean.FALSE);
       // Validate locality against boundary service
       validateBoundaryCode(boundarySearchResponse, request.getPlan());
       // Validate activities
       validateActivities(request);
       // Validate plan configuration existence
       validatePlanConfigurationExistence(request);
       // Validate resources
       validateResources(request);
       // Validate resource-activity linkage
       validateResourceActivityLinkage(request);
       // Validate target-activity linkage
       validateTargetActivityLinkage(request);
       // Validate dependencies
       validateActivityDependencies(request);
       // Validate Target's Metrics against MDMS
       validateTargetMetrics(request, mdmsData);
       // Validate Metric Detail's Unit against MDMS
       validateMetricDetailUnit(request, mdmsData);
       // Validate if campaign id exists against project factory
       validateCampaignId(campaignResponse);
       // Validate the user information in the request
       commonUtil.validateUserInfo(request.getRequestInfo());
       // Validate plan-employee assignment and jurisdiction is request is from Resource Estimation Consumer
       validatePlanEmployeeAssignmentAndJurisdiction(request);
   }
   ```

10. **Method: `validateBoundaryCode`**
    - **Description**: Validates the boundary code provided in plan request against boundary service.
    - **Parameters**: 
      - `BoundarySearchResponse boundarySearchResponse`: response from the boundary service.
      - `Plan plan`: Plan record whose locality is to be validated.
    - **Line Numbers**: 62-66
    ```java
    private void validateBoundaryCode(BoundarySearchResponse boundarySearchResponse, Plan plan) {
        HierarchyRelation tenantBoundary = boundarySearchResponse.getTenantBoundary().get(0);
        if (CollectionUtils.isEmpty(tenantBoundary.getBoundary())) {
            throw new CustomException(NO_BOUNDARY_DATA_FOUND_FOR_GIVEN_BOUNDARY_CODE_CODE, NO_BOUNDARY_DATA_FOUND_FOR_GIVEN_BOUNDARY_CODE_MESSAGE);
        }
        // Enrich the boundary ancestral path and jurisdiction mapping for the provided boundary code
        planEnricher.enrichBoundaryAncestralPath(plan, tenantBoundary);
    }
    ```

### Summary
The identified methods and their descriptions provide relevant context for understanding the `CampaignIntegrationUtil` class and its interactions with other components, particularly in relation to validating and processing campaign data. The snippets from the `PlanConfigurationValidator` and `PlanValidator` classes further illustrate how campaign and plan configurations are validated against various criteria, including MDMS data and boundary conditions.

### Relevant Code Snippets

#### From `health-services/resource-generator/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java`

1. **Method: `performCampaignSearch`**
   - **Line Numbers:** 30-36
   - **Description:** Performs a campaign search based on the provided plan configuration request. This method builds a campaign search request using the integration utility, fetches the search result from the service request repository, and returns it.
   - **Parameters:** 
     - `PlanConfigurationRequest planConfigurationRequest`: The request object containing configuration details for the campaign search.
   - **Return Value:** Returns the response object containing the result of the campaign search.

2. **Method: `updateResourcesInProjectFactory`**
   - **Line Numbers:** 38-50
   - **Description:** Updates resources in the Project Factory by calling an external API with the given plan configuration request and file store ID. Logs the operation status.
   - **Parameters:** 
     - `PlanConfigurationRequest planConfigurationRequest`: The plan configuration request details.
     - `String fileStoreId`: The file store ID to update.
   - **Throws:** `CustomException` if the API call fails.

3. **Method: `createProjectFactoryDataCall`**
   - **Line Numbers:** 52-66
   - **Description:** Sends a data creation request to the Project Factory service using the provided plan and campaign details.
   - **Parameters:** 
     - `PlanConfigurationRequest planConfigurationRequest`: The plan configuration request containing campaign data.
     - `CampaignResponse campaignResponse`: The response with additional campaign information.
   - **Throws:** `CustomException` if the data creation call fails.

4. **Method: `buildCampaignRequestForSearch`**
   - **Line Numbers:** 68-76
   - **Description:** Builds a campaign search request based on the provided plan configuration request.
   - **Parameters:** 
     - `PlanConfigurationRequest planConfigurationRequest`: The plan configuration request containing necessary information for building the search request.
   - **Return Value:** Returns the campaign search request object built for searching campaigns.

5. **Method: `parseCampaignResponse`**
   - **Line Numbers:** 78-82
   - **Description:** Parses an object representing campaign response into a CampaignResponse object.
   - **Parameters:** 
     - `Object campaignResponse`: The object representing campaign response to be parsed.
   - **Return Value:** Returns a `CampaignResponse` object parsed from the campaignResponse.

#### From `health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java`

1. **Method: `uploadFileAndIntegrateCampaign`**
   - **Line Numbers:** 90-116
   - **Description:** Uploads a converted file and integrates campaign details if configured to do so.
   - **Parameters:** 
     - `PlanConfigurationRequest planConfigurationRequest`: The request containing configuration details including tenant ID.
     - `Workbook workbook`: The workbook containing data to be uploaded and integrated.
     - `String filestoreId`: The ID of the file in the file store.

2. **Method: `processSheets`**
   - **Line Numbers:** 118-160
   - **Description:** Processes each sheet in the workbook for plan configuration data. Validates column names, processes rows, and integrates campaign details.
   - **Parameters:** 
     - `PlanConfigurationRequest request`: The request containing configuration details including tenant ID.
     - `String fileStoreId`: The ID of the uploaded file in the file store.
     - `Object campaignResponse`: The response object containing campaign details.
     - `Workbook excelWorkbook`: The workbook containing sheets to be processed.

3. **Method: `batchProcessCensusRecords`**
   - **Line Numbers:** 162-182
   - **Description:** Processes census records in batches based on the given plan configuration request.
   - **Parameters:** 
     - `PlanConfigurationRequest planConfigurationRequest`: The request containing plan configuration details.
     - `Map<String, Object> boundaryCodeToCensusAdditionalDetails`: A map to store additional census details indexed by boundary code.

4. **Method: `getBoundaryCodeList`**
   - **Line Numbers:** 184-197
   - **Description:** Retrieves a list of boundary codes based on the given plan configuration, campaign details, and request information.
   - **Parameters:** 
     - `PlanConfigurationRequest planConfigurationRequest`: The request containing configuration details including tenant ID.
     - `CampaignResponse campaign`: The campaign response object containing campaign details.
   - **Return Value:** A list of boundary codes corresponding to the specified hierarchy type and tenant ID.

These methods and their descriptions provide relevant context for understanding the functionality of the `CampaignIntegrationUtil` class and its interactions with other components, particularly in relation to campaign management and data processing.

</details>



<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-04-03T06:26:16Z
author_association: CONTRIBUTOR

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-04-02T11:19:14Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- This is an auto-generated comment: skip review by coderabbit.ai -->

> [!IMPORTANT]
> ## Review skipped
> 
> Auto reviews are disabled on base/target branches other than the default branch.
> 
> 
> 
> Please check the settings in the CodeRabbit UI or the `.coderabbit.yaml` file in this repository. To trigger a single review, invoke the `@coderabbitai review` command.
> 
> You can disable this status message by setting the `reviews.review_status` to `false` in the CodeRabbit configuration file.

<!-- end of auto-generated comment: skip review by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough
The changes enable asynchronous execution with the addition of `@EnableAsync` to the main application. New error and service constants have been introduced while some obsolete ones have been removed. A draft processing feature has been implemented with new service and controller classes along with supporting models. Enhancements have also been made in utility classes to support asynchronous operations, workbook processing, campaign search integration, and file handling. Import statements have been reorganized for clarity.

## Changes

| File(s) | Change Summary |
|---------|----------------|
| `.../processor/Main.java` | Added `@EnableAsync` annotation to enable asynchronous method execution. |
| `.../processor/config/ErrorConstants.java`<br>`.../processor/config/ServiceConstants.java` | Added new constants for workbook read errors and draft statuses; removed obsolete schema and file template constants. |
| `.../processor/service/DraftService.java`<br>`.../processor/web/controllers/DraftController.java`<br>`.../processor/web/models/DraftDetails.java`<br>`.../processor/web/models/DraftRequest.java`<br>`.../processor/util/PlanConfigurationUtil.java` | Introduced new draft processing components, including an asynchronous service for creating draft plans, web endpoint to trigger draft creation, data models for draft details, and plan configuration utilities for draft file handling. |
| `.../processor/service/ExcelParser.java`<br>`.../processor/service/ResourceEstimationService.java`<br>`.../processor/util/CampaignIntegrationUtil.java`<br>`.../processor/util/OutputEstimationGenerationUtil.java`<br>`.../processor/util/FilestoreUtil.java`<br>`.../processor/web/controllers/FileController.java` | Modified method visibilities and signatures, enhanced workbook processing with conditional logic and file retrieval, restructured campaign search flows, added draft output file processing, and reorganized import statements. |

## Sequence Diagram(s)
```mermaid
sequenceDiagram
    participant C as Client
    participant DC as DraftController
    participant DS as DraftService
    participant CP as CampaignIntegrationUtil
    participant EP as ExcelParser
    participant OE as OutputEstimationGenerationUtil
    participant PC as PlanConfigurationUtil

    C->>DC: POST /draft (DraftRequest)
    DC->>DS: createDraftPlans(draftRequest)
    DS->>EP: getWorkbookFromFilestoreId(filestoreId, tenantId)
    DS->>CP: performCampaignSearch(planConfigRequest)
    DS->>OE: processDraftOutputFile(workbook, request)
    DS->>PC: setOrAddFileForDraft(planConfigRequest, fileStoreId, type)
    DS-->>DC: Acknowledge processing start
    DC-->>C: ResponseEntity("Draft processing started")
```

## Suggested Reviewers
- sathishp-eGov
- kavi-egov
- shashwat-egov

## Poem
> I’m a rabbit in code, hopping through the night,  
> Async leaps and draft dreams shining bright,  
> Constants guide each error and task,  
> New features bloom behind every mask,  
> With every change, I dance with glee—  
> CodeRabbit hops to innovation, wild and free! 🐇

<!-- walkthrough_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=egovernments/health-campaign-services&utm_content=1482):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai plan` to trigger planning for file edits and PR creation.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR
user: login: Priyanka-eGov
created_at: 2025-04-03T05:15:38Z
body: @coderabbitai review
author_association: COLLABORATOR
user: login: coderabbitai[bot]
created_at: 2025-04-03T05:15:44Z
body: <!-- This is an auto-generated reply by CodeRabbit -->
<details>
<summary>:white_check_mark: Actions performed</summary>

Review triggered.

> Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

</details>
author_association: CONTRIBUTOR