Skip to content

Commit

Permalink
Merge pull request #1409 from egovernments/HCMPRE-2264-changes
Browse files Browse the repository at this point in the history
Modifying implementation for updatingServingPopulation in planFacility  and censusFacilityConsumer in census
  • Loading branch information
shashwat-egov authored Feb 19, 2025
2 parents ee41df3 + e717131 commit 101dd6b
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,46 +53,79 @@ public FacilityCatchmentConsumer(ObjectMapper objectMapper, CensusService servic
@KafkaListener(topics = {"${plan.facility.update.topic}"})
public void listen(Map<String, Object> consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) {
try {
// Convert consumer record to DTO
PlanFacilityRequestDTO planFacilityRequestDTO = objectMapper.convertValue(consumerRecord, PlanFacilityRequestDTO.class);
PlanFacilityDTO planFacilityDTO = planFacilityRequestDTO.getPlanFacilityDTO();

CensusResponse censusResponse = service.search(commonUtil.getCensusSearchRequest(planFacilityDTO.getTenantId(), planFacilityDTO.getPlanConfigurationId(), planFacilityDTO.getServiceBoundaries(), planFacilityDTO.getInitiallySetServiceBoundaries(), planFacilityRequestDTO.getRequestInfo()));
// Extract current and initial service boundaries
List<String> initialServiceBoundaries = planFacilityDTO.getInitiallySetServiceBoundaries();
List<String> currentServiceBoundaries = List.of(planFacilityDTO.getServiceBoundaries().split(COMMA_DELIMITER));

// Determine boundaries that require census record updates
Set<String> boundariesToBeSearched = initialServiceBoundaries.size() > currentServiceBoundaries.size()
? commonUtil.getUniqueElements(initialServiceBoundaries, currentServiceBoundaries)
: commonUtil.getUniqueElements(currentServiceBoundaries, initialServiceBoundaries);

// Fetch existing census records for the identified boundaries
CensusResponse censusResponse = service.search(commonUtil.getCensusSearchRequest(planFacilityDTO.getTenantId(), planFacilityDTO.getPlanConfigurationId(), boundariesToBeSearched, planFacilityRequestDTO.getRequestInfo()));
List<Census> censusFromSearch = censusResponse.getCensus();

// Fetch boundary type hierarchy for enriching jurisdiction mapping
BoundaryTypeHierarchyResponse boundaryTypeHierarchyResponse = boundaryUtil.fetchBoundaryHierarchy(planFacilityRequestDTO.getRequestInfo(), censusFromSearch.get(0).getTenantId(), censusFromSearch.get(0).getHierarchyType());

// Extract facility details from the request
String facilityId = planFacilityRequestDTO.getPlanFacilityDTO().getFacilityId();
String facilityName = planFacilityRequestDTO.getPlanFacilityDTO().getFacilityName();

Set<String> boundariesWithFacility = new HashSet<>(List.of(planFacilityDTO.getServiceBoundaries().split(COMMA_DELIMITER)));
Set<String> boundariesWithNoFacility = new HashSet<>(planFacilityDTO.getInitiallySetServiceBoundaries());

censusFromSearch.forEach(census -> {
String boundaryCode = census.getBoundaryCode();

if (!boundariesWithFacility.contains(boundaryCode)) {

// Unassigning facilities to the boundaries which were initially assigned that facility
census.setAdditionalDetails(commonUtil.removeFieldFromAdditionalDetails(census.getAdditionalDetails(), FACILITY_ID_FIELD));
census.setAdditionalDetails(commonUtil.removeFieldFromAdditionalDetails(census.getAdditionalDetails(), FACILITY_NAME_FIELD));
census.setFacilityAssigned(Boolean.FALSE);
census.setPartnerAssignmentValidationEnabled(Boolean.FALSE);

} else if (!boundariesWithNoFacility.contains(boundaryCode)) {

// Assigning facilities to the newly added boundaries in the update request.
census.setAdditionalDetails(commonUtil.updateFieldInAdditionalDetails(census.getAdditionalDetails(), FACILITY_ID_FIELD, facilityId));
census.setAdditionalDetails(commonUtil.updateFieldInAdditionalDetails(census.getAdditionalDetails(), FACILITY_NAME_FIELD, facilityName));
census.setFacilityAssigned(Boolean.TRUE);
census.setPartnerAssignmentValidationEnabled(Boolean.FALSE);
}
});
// Determine whether to assign or unassign facilities based on initial and current service boundaries.
List<Census> updatedCensusRecords = initialServiceBoundaries.size() > currentServiceBoundaries.size()
? unassignFacilities(censusFromSearch)
: assignFacilities(censusFromSearch, facilityId, facilityName);

// Enrich jurisdiction mapping in census for indexer
enrichment.enrichJurisdictionMapping(censusFromSearch, boundaryTypeHierarchyResponse.getBoundaryHierarchy().get(0));
repository.bulkUpdate(BulkCensusRequest.builder().requestInfo(planFacilityRequestDTO.getRequestInfo()).census(censusFromSearch).build());
enrichment.enrichJurisdictionMapping(updatedCensusRecords, boundaryTypeHierarchyResponse.getBoundaryHierarchy().get(0));
repository.bulkUpdate(BulkCensusRequest.builder().requestInfo(planFacilityRequestDTO.getRequestInfo()).census(updatedCensusRecords).build());

} catch (Exception exception) {
log.error("Error in census consumer", exception);
}
}

/**
* Unassigns facilities from census records by removing facility-related fields.
*
* @param censusList List of census records to be updated.
* @return Updated list of census records with facility fields removed.
*/
private List<Census> unassignFacilities(List<Census> censusList) {
censusList.forEach(census -> {

// Unassigning facilities to the boundaries which were initially assigned that facility
census.setAdditionalDetails(commonUtil.removeFieldFromAdditionalDetails(census.getAdditionalDetails(), FACILITY_ID_FIELD));
census.setAdditionalDetails(commonUtil.removeFieldFromAdditionalDetails(census.getAdditionalDetails(), FACILITY_NAME_FIELD));
census.setFacilityAssigned(Boolean.FALSE);
census.setPartnerAssignmentValidationEnabled(Boolean.FALSE);
});
return censusList;
}

/**
* Assigns facilities to census records by adding facility-related fields.
*
* @param censusList List of census records to be updated.
* @param facilityId ID of the facility to be assigned.
* @param facilityName Name of the facility to be assigned.
* @return Updated list of census records with facility details added.
*/
private List<Census> assignFacilities(List<Census> censusList, String facilityId, String facilityName) {
censusList.forEach(census -> {

// Assigning facilities to the newly added boundaries in the update request.
census.setAdditionalDetails(commonUtil.updateFieldInAdditionalDetails(census.getAdditionalDetails(), FACILITY_ID_FIELD, facilityId));
census.setAdditionalDetails(commonUtil.updateFieldInAdditionalDetails(census.getAdditionalDetails(), FACILITY_NAME_FIELD, facilityName));
census.setFacilityAssigned(Boolean.TRUE);
census.setPartnerAssignmentValidationEnabled(Boolean.FALSE);
});
return censusList;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;

import static digit.config.ServiceConstants.*;

Expand Down Expand Up @@ -96,21 +97,18 @@ public Map<String, Object> removeFieldFromAdditionalDetails(Object additionalDet
* Creates the census search request for the provided details.
* @param tenantId
* @param planConfigId
* @param serviceBoundary
* @param boundariesToBeSearched
* @param requestInfo
* @return
*/
public CensusSearchRequest getCensusSearchRequest(String tenantId, String planConfigId, String serviceBoundary, List<String> initiallySetServiceBoundaries, RequestInfo requestInfo) {
Set<String> areaCodesForSearch = new HashSet<>();

areaCodesForSearch.addAll(Arrays.asList(serviceBoundary.split(",")));
areaCodesForSearch.addAll(initiallySetServiceBoundaries);
public CensusSearchRequest getCensusSearchRequest(String tenantId, String planConfigId, Set<String> boundariesToBeSearched, RequestInfo requestInfo) {

CensusSearchCriteria searchCriteria = CensusSearchCriteria.builder()
.tenantId(tenantId)
.source(planConfigId)
.areaCodes(areaCodesForSearch.stream().toList())
.areaCodes(boundariesToBeSearched.stream().toList())
.offset(0)
.limit(areaCodesForSearch.size())
.limit(boundariesToBeSearched.size())
.build();

return CensusSearchRequest.builder().requestInfo(requestInfo).censusSearchCriteria(searchCriteria).build();
Expand Down Expand Up @@ -148,4 +146,18 @@ public PGobject convertToPgObject(Object additionalDetails) {

return pGobject;
}

/**
* Finds the unique elements in the primary list that are not present in the secondary list.
* This can be used to determine newly added or missing elements between two lists.
*
* @param primaryList The main list containing elements to be checked.
* @param secondaryList The reference list to compare against.
* @return A set containing elements that are in primaryList but not in secondaryList.
*/
public Set<String> getUniqueElements(List<String> primaryList, List<String> secondaryList) {
return primaryList.stream()
.filter(element -> !secondaryList.contains(element))
.collect(Collectors.toSet());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,16 +108,20 @@ public void enrichPlanFacilityUpdate(PlanFacilityRequest planFacilityRequest) {
}

/**
* Enriches serving population based on the serving boundaries provided.
* Enriches the serving population of a PlanFacility by fetching census data
* for newly added or removed service boundaries.
*
* @param planFacilityRequest plan facility request whose serving population is to be enriched.
*/
private void enrichServingPopulation(PlanFacilityRequest planFacilityRequest) {
PlanFacility planFacility = planFacilityRequest.getPlanFacility();
List<String> initialServingBoundaries = planFacility.getInitiallySetServiceBoundaries();
List<String> currentServingBoundaries = planFacility.getServiceBoundaries();

// Prepare list of boundaries whose census records are to be fetched
Set<String> boundariesToBeSearched = new HashSet<>(planFacility.getServiceBoundaries());
boundariesToBeSearched.addAll(planFacility.getInitiallySetServiceBoundaries());
// Determine which boundaries have been added or removed
Set<String> boundariesToBeSearched = initialServingBoundaries.size() > currentServingBoundaries.size()
? commonUtil.getUniqueElements(initialServingBoundaries, currentServingBoundaries)
: commonUtil.getUniqueElements(currentServingBoundaries, initialServingBoundaries);

if(!CollectionUtils.isEmpty(boundariesToBeSearched)) {
CensusSearchCriteria censusSearchCriteria = CensusSearchCriteria.builder()
Expand All @@ -132,13 +136,14 @@ private void enrichServingPopulation(PlanFacilityRequest planFacilityRequest) {
.censusSearchCriteria(censusSearchCriteria)
.build());

// Creates a population map based on the confirmed target population of the boundary
Map<String, Long> boundaryToPopMap = getPopulationMap(censusResponse.getCensus());
// Create a map of serving boundaries with its confirmed total population.
Map<String, Long> boundaryToPopulationMap = getPopulationMap(censusResponse.getCensus());

// Get existing servingPopulation or default to 0
BigDecimal servingPopulation = commonUtil.extractFieldsFromJsonObject(planFacility.getAdditionalDetails(), SERVING_POPULATION_CODE, BigDecimal.class);

updateServingPopulation(boundariesToBeSearched, planFacility, boundaryToPopMap, servingPopulation);
// Update the serving population in the PlanFacility
updateServingPopulation(planFacility, boundaryToPopulationMap, servingPopulation);
}
}

Expand Down Expand Up @@ -174,33 +179,26 @@ private Map<String, Long> getPopulationMap(List<Census> censusList) {
}

/**
* Updates the serving population of a plan facility based on changes in service boundaries.
* Updates the serving population for a given PlanFacility based on changes in service boundaries.
* Subtracts population for removed boundaries and adds population for newly added ones.
*
* @param boundariesToBeSearched Set of boundary codes to evaluate.
* @param planFacility Plan facility whose serving population is updated.
* @param boundaryToPopMap Map of boundary codes to population values.
* @param servingPopulation Current serving population to be adjusted.
*/
private void updateServingPopulation(Set<String> boundariesToBeSearched, PlanFacility planFacility, Map<String, Long> boundaryToPopMap, BigDecimal servingPopulation) {

// Retrieve the plan facility's current and initial service boundaries.
Set<String> currentServiceBoundaries = new HashSet<>(planFacility.getServiceBoundaries());
Set<String> initialServiceBoundaries = new HashSet<>(planFacility.getInitiallySetServiceBoundaries());

// Adjust the serving population based on boundary changes.
for(String boundary : boundariesToBeSearched) {
Long totalPopulation = boundaryToPopMap.get(boundary);

if (!currentServiceBoundaries.contains(boundary)) {
// If the boundary was removed from service, subtract its population.
servingPopulation = servingPopulation.subtract(BigDecimal.valueOf(totalPopulation));
} else if (!initialServiceBoundaries.contains(boundary)) {
// If the boundary is newly added, add its population.
servingPopulation = servingPopulation.add(BigDecimal.valueOf(totalPopulation));
}
private void updateServingPopulation(PlanFacility planFacility, Map<String, Long> boundaryToPopMap, BigDecimal servingPopulation) {

// Get sum of confirmed target populations corresponding to the newly added/removed serving boundaries.
Long totalPopulation = 0L;
for(Long population : boundaryToPopMap.values()) {
totalPopulation = totalPopulation + population;
}

// Adjust the serving population based on whether boundaries are added or removed.
servingPopulation = planFacility.getInitiallySetServiceBoundaries().size() > planFacility.getServiceBoundaries().size()
? servingPopulation.subtract(BigDecimal.valueOf(totalPopulation)) // Subtract if boundaries are removed.
: servingPopulation.add(BigDecimal.valueOf(totalPopulation)); // Add if boundaries are added.

// Update the plan facility's additional details with the new serving population.
Map<String, Object> fieldToUpdate = new HashMap<>();
fieldToUpdate.put(SERVING_POPULATION_CODE, servingPopulation);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static digit.config.ServiceConstants.*;

Expand Down Expand Up @@ -304,4 +305,17 @@ public List<String> getBoundaryCodeFromAncestralPath(String boundaryAncestralPat
return Arrays.asList(boundaryAncestralPath.split(PIPE_REGEX));
}

/**
* Finds the unique elements in the primary list that are not present in the secondary list.
* This can be used to determine newly added or missing elements between two lists.
*
* @param primaryList The main list containing elements to be checked.
* @param secondaryList The reference list to compare against.
* @return A set containing elements that are in primaryList but not in secondaryList.
*/
public Set<String> getUniqueElements(List<String> primaryList, List<String> secondaryList) {
return primaryList.stream()
.filter(element -> !secondaryList.contains(element))
.collect(Collectors.toSet());
}
}

0 comments on commit 101dd6b

Please sign in to comment.