Java tutorial
/* * eGov SmartCity eGovernance suite aims to improve the internal efficiency,transparency, * accountability and the service delivery of the government organizations. * * Copyright (C) 2017 eGovernments Foundation * * The updated version of eGov suite of products as by eGovernments Foundation * is available at http://www.egovernments.org * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/ or * http://www.gnu.org/licenses/gpl.html . * * In addition to the terms of the GPL license to be adhered to in using this * program, the following additional terms are to be complied with: * * 1) All versions of this program, verbatim or modified must carry this * Legal Notice. * Further, all user interfaces, including but not limited to citizen facing interfaces, * Urban Local Bodies interfaces, dashboards, mobile applications, of the program and any * derived works should carry eGovernments Foundation logo on the top right corner. * * For the logo, please refer http://egovernments.org/html/logo/egov_logo.png. * For any further queries on attribution, including queries on brand guidelines, * please contact contact@egovernments.org * * 2) Any misrepresentation of the origin of the material is prohibited. It * is required that all modified versions of this material be marked in * reasonable ways as different from the original version. * * 3) This license does not grant any rights to any user of the program * with regards to rights under trademark law for use of the trade names * or trademarks of eGovernments Foundation. * * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. * */ package org.egov.ptis.service.es; import static org.egov.ptis.constants.PropertyTaxConstants.BIGDECIMAL_100; import static org.egov.ptis.constants.PropertyTaxConstants.DASHBOARD_GROUPING_BILLCOLLECTORWISE; import static org.egov.ptis.constants.PropertyTaxConstants.DASHBOARD_GROUPING_CITYWISE; import static org.egov.ptis.constants.PropertyTaxConstants.DASHBOARD_GROUPING_DISTRICTWISE; import static org.egov.ptis.constants.PropertyTaxConstants.DASHBOARD_GROUPING_GRADEWISE; import static org.egov.ptis.constants.PropertyTaxConstants.DASHBOARD_GROUPING_REGIONWISE; import static org.egov.ptis.constants.PropertyTaxConstants.DASHBOARD_GROUPING_REVENUEINSPECTORWISE; import static org.egov.ptis.constants.PropertyTaxConstants.DASHBOARD_GROUPING_REVENUEOFFICERWISE; import static org.egov.ptis.constants.PropertyTaxConstants.DASHBOARD_GROUPING_WARDWISE; import static org.egov.ptis.constants.PropertyTaxConstants.DATEFORMATTER_YYYY_MM_DD; import static org.egov.ptis.constants.PropertyTaxConstants.PROPERTY_TAX_INDEX_NAME; import static org.egov.ptis.constants.PropertyTaxConstants.COLLECTION_ACHIEVEMENTS_INDEX_NAME; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.commons.lang3.StringUtils; import org.egov.commons.CFinancialYear; import org.egov.commons.service.CFinancialYearService; import org.egov.infra.admin.master.entity.es.CityIndex; import org.egov.infra.utils.DateUtils; import org.egov.ptis.bean.dashboard.CollectionDetails; import org.egov.ptis.bean.dashboard.CollectionDetailsRequest; import org.egov.ptis.bean.dashboard.DCBDetails; import org.egov.ptis.bean.dashboard.DemandVariance; import org.egov.ptis.bean.dashboard.DemandVariationDetails; import org.egov.ptis.bean.dashboard.PropertyTaxDefaultersRequest; import org.egov.ptis.bean.dashboard.TaxDefaulters; import org.egov.ptis.bean.dashboard.TaxPayerDetails; import org.egov.ptis.bean.dashboard.TaxPayerResponseDetails; import org.egov.ptis.constants.PropertyTaxConstants; import org.egov.ptis.domain.entity.es.BillCollectorIndex; import org.egov.ptis.domain.entity.es.CollectionAchievementsIndex; import org.egov.ptis.domain.entity.es.PropertyTaxIndex; import org.egov.ptis.repository.es.PropertyTaxIndexRepository; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.aggregations.AggregationBuilder; import org.elasticsearch.search.aggregations.AggregationBuilders; import org.elasticsearch.search.aggregations.Aggregations; import org.elasticsearch.search.aggregations.bucket.terms.StringTerms; import org.elasticsearch.search.aggregations.bucket.terms.Terms; import org.elasticsearch.search.aggregations.bucket.terms.TermsBuilder; import org.elasticsearch.search.aggregations.metrics.sum.Sum; import org.elasticsearch.search.sort.FieldSortBuilder; import org.elasticsearch.search.sort.SortOrder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.elasticsearch.core.ElasticsearchTemplate; import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; import org.springframework.data.elasticsearch.core.query.SearchQuery; import org.springframework.stereotype.Service; @Service public class PropertyTaxElasticSearchIndexService { private static final String REBATE_STR = "rebate"; private static final String TOTAL_COLL_STR = "totalColl"; private static final String ADVANCE_COLL_STR = "advanceColl"; private static final String CURRENT_INT_COLL = "currentIntColl"; private static final String ARREAR_INT_COLL = "arrearIntColl"; private static final String CURRENT_COLL_STR = "currentColl"; private static final String ARREAR_COLL_STR = "arrearColl"; private static final String TOTAL_DMD_STR = "totalDmd"; private static final String CURRENT_INT_DMD = "currentIntDmd"; private static final String ARREAR_INT_DMD = "arrearIntDmd"; private static final String CURRENT_DMD = "currentDmd"; private static final String ARREAR_DMD = "arrearDmd"; private static final String CURR_INTEREST_DMD = "curr_interest_dmd"; private static final String ARREAR_INTEREST_DMD = "arrear_interest_dmd"; private static final String CURR_DMD = "curr_dmd"; private static final String ARREAR_DMD_STR = "arrear_dmd"; private static final String CURRENT_INTEREST_COLLECTION = "currentInterestCollection"; private static final String ARREAR_INTEREST_COLLECTION = "arrearInterestCollection"; private static final String ANNUAL_COLLECTION = "annualCollection"; private static final String ARREAR_COLLECTION = "arrearCollection"; private static final String IS_ACTIVE = "isActive"; private static final String IS_EXEMPTED = "isExempted"; private static final String CITY_GRADE = "cityGrade"; private static final String CITY_CODE = "cityCode"; private static final String DISTRICT_NAME = "districtName"; private static final String REGION_NAME = "regionName"; private static final String BY_AGGREGATION_FIELD = "by_aggregationField"; private static final String CITY_NAME = "cityName"; private static final String REVENUE_WARD = "revenueWard"; private static final String TOTAL_COLLECTION = "total_collection"; private static final String TOTAL_DEMAND = "totalDemand"; private static final String ARREAR_DEMAND = "arrearDemand"; private static final String CURRENT_DEMAND = "currentDemand"; private static final String TOTALDEMAND = "totaldemand"; private static final String BY_TYPE = "ByType"; private static final String BY_APPLICATION = "By_Applicationtype"; private static final String APPLICATION_TYPE = "applicationType"; private static final String DEMAND_DATE = "demandDate"; private static final String PRIMARY_DEMAND = "Primary Demand"; private static final String DEMAND_VARIATION = "demandvariation"; private static final String PT_NEW_ASSMNT = "New_Assessment"; private static final String PT_ALTER_ASSMNT = "Alter_Assessment"; private final PropertyTaxIndexRepository propertyTaxIndexRepository; @Autowired private CFinancialYearService cFinancialYearService; @Autowired private ElasticsearchTemplate elasticsearchTemplate; @Autowired private CollectionIndexElasticSearchService collectionIndexElasticSearchService; @Autowired public PropertyTaxElasticSearchIndexService(final PropertyTaxIndexRepository propertyTaxIndexRepository) { this.propertyTaxIndexRepository = propertyTaxIndexRepository; } public Page<PropertyTaxIndex> findByConsumercode(final String consumerCode) { return propertyTaxIndexRepository.findByConsumerCode(consumerCode, new PageRequest(0, 10)); } /** * API returns the current year total demand from Property Tax index * * @return BigDecimal */ public BigDecimal getTotalDemand() { final BoolQueryBuilder boolQuery = QueryBuilders.boolQuery() .filter(QueryBuilders.rangeQuery(TOTAL_DEMAND).from(0).to(null)) .filter(QueryBuilders.matchQuery(IS_ACTIVE, true)) .filter(QueryBuilders.matchQuery(IS_EXEMPTED, false)); final SearchQuery searchQuery = new NativeSearchQueryBuilder().withIndices(PROPERTY_TAX_INDEX_NAME) .withQuery(boolQuery).addAggregation(AggregationBuilders.sum(TOTALDEMAND).field(TOTAL_DEMAND)) .build(); final Aggregations aggregations = elasticsearchTemplate.query(searchQuery, response -> response.getAggregations()); final Sum aggr = aggregations.get(TOTALDEMAND); return BigDecimal.valueOf(aggr.getValue()).setScale(0, BigDecimal.ROUND_HALF_UP); } /** * Populates the consolidated demand information in CollectionIndexDetails * * @param collectionDetailsRequest * @param collectionIndexDetails */ public void getConsolidatedDemandInfo(final CollectionDetailsRequest collectionDetailsRequest, final CollectionDetails collectionIndexDetails) { Date fromDate; Date toDate; final CFinancialYear currFinYear = cFinancialYearService.getFinancialYearByDate(new Date()); /** * For fetching total demand between the date ranges if dates are sent in the request, consider fromDate and toDate+1 , * else calculate from current year start date till current date+1 day */ if (StringUtils.isNotBlank(collectionDetailsRequest.getFromDate()) && StringUtils.isNotBlank(collectionDetailsRequest.getToDate())) { fromDate = DateUtils.getDate(collectionDetailsRequest.getFromDate(), "yyyy-MM-dd"); toDate = DateUtils.getDate(collectionDetailsRequest.getToDate(), "yyyy-MM-dd"); } else { fromDate = DateUtils.startOfDay(currFinYear.getStartingDate()); toDate = new Date(); } final BigDecimal totalDemand = getTotalDemandBasedOnInputFilters(collectionDetailsRequest); final int noOfMonths = DateUtils.noOfMonthsBetween(fromDate, toDate) + 1; collectionIndexDetails.setTotalDmd(totalDemand); // Proportional Demand = (totalDemand/12)*noOfmonths final BigDecimal proportionalDemand = totalDemand.divide(BigDecimal.valueOf(12), BigDecimal.ROUND_HALF_UP) .multiply(BigDecimal.valueOf(noOfMonths)); collectionIndexDetails.setCytdDmd(proportionalDemand.setScale(0, BigDecimal.ROUND_HALF_UP)); collectionIndexDetails.setTotalAssessments( collectionIndexElasticSearchService.getTotalAssessmentsCount(collectionDetailsRequest)); if (proportionalDemand.compareTo(BigDecimal.ZERO) > 0) // performance = (current year tilldate collection * 100)/(proportional demand) collectionIndexDetails.setPerformance( collectionIndexDetails.getCytdColl().multiply(PropertyTaxConstants.BIGDECIMAL_100) .divide(proportionalDemand, 1, BigDecimal.ROUND_HALF_UP)); // variance = ((currentYearCollection - lastYearCollection)*100)/lastYearCollection BigDecimal variation; if (collectionIndexDetails.getLytdColl().compareTo(BigDecimal.ZERO) == 0) variation = BIGDECIMAL_100; else variation = collectionIndexDetails.getCytdColl().subtract(collectionIndexDetails.getLytdColl()) .multiply(BIGDECIMAL_100) .divide(collectionIndexDetails.getLytdColl(), 1, BigDecimal.ROUND_HALF_UP); collectionIndexDetails.setLyVar(variation); } /** * Returns total demand from Property tax index, based on input filters * * @param collectionDetailsRequest * @return */ public BigDecimal getTotalDemandBasedOnInputFilters(final CollectionDetailsRequest collectionDetailsRequest) { final BoolQueryBuilder boolQuery = prepareWhereClause(collectionDetailsRequest) .filter(QueryBuilders.matchQuery(IS_ACTIVE, true)) .filter(QueryBuilders.matchQuery(IS_EXEMPTED, false)); final SearchQuery searchQueryColl = new NativeSearchQueryBuilder().withIndices(PROPERTY_TAX_INDEX_NAME) .withQuery(boolQuery).addAggregation(AggregationBuilders.sum(TOTALDEMAND).field(TOTAL_DEMAND)) .build(); final Aggregations collAggr = elasticsearchTemplate.query(searchQueryColl, response -> response.getAggregations()); final Sum aggr = collAggr.get(TOTALDEMAND); return BigDecimal.valueOf(aggr.getValue()).setScale(0, BigDecimal.ROUND_HALF_UP); } /** * API prepares the data to push into CollectionAchievements index * @param collectionDetailsRequest * @param currFinYear * @param city * @return list */ public List<TaxPayerDetails> prepareDataForAchievementsIndex(CollectionDetailsRequest collectionDetailsRequest, CFinancialYear currFinYear, CityIndex city) { List<TaxPayerDetails> wardWiseTaxProducers; Map<String, TaxPayerDetails> wardWiseTaxPayersDetails = new HashMap<>(); Map<String, List<TaxPayerDetails>> billCollectorWiseMap = new LinkedHashMap<>(); List<TaxPayerDetails> taxPayerDetailsList = new ArrayList<>(); List<TaxPayerDetails> userWiseTaxPayerDetails = new ArrayList<>(); wardWiseTaxProducers = returnUlbWiseAggregationResults(collectionDetailsRequest, PROPERTY_TAX_INDEX_NAME, false, TOTAL_COLLECTION, 250, true, currFinYear); // Get ward wise tax payers details prepareWardWiseTaxPayerDetails(wardWiseTaxProducers, wardWiseTaxPayersDetails); // Group the revenue ward details by bill collector prepareBillCollectorWiseMapData(collectionDetailsRequest, wardWiseTaxPayersDetails, billCollectorWiseMap, taxPayerDetailsList); // Prepare Bill Collector wise tax payers details prepareTaxersInfoForBillCollectors(collectionDetailsRequest, billCollectorWiseMap, userWiseTaxPayerDetails); for (TaxPayerDetails taxPayerDetails : userWiseTaxPayerDetails) { taxPayerDetails.setRegionName(city.getRegionname()); taxPayerDetails.setDistrictName(city.getDistrictname()); taxPayerDetails.setUlbGrade(city.getCitygrade()); taxPayerDetails.setUlbName(city.getName()); taxPayerDetails.setUlbCode(city.getCitycode()); } return userWiseTaxPayerDetails; } public Map<String, List<TaxPayerDetails>> getCollectionRankings( CollectionDetailsRequest collectionDetailsRequest) { Map<String, List<TaxPayerDetails>> rankingsMap = new LinkedHashMap<>(); List<TaxPayerDetails> taxPayerDetailsList = new ArrayList<>(); TaxPayerDetails taxPayerDetails; String groupingField = StringUtils.EMPTY; BoolQueryBuilder boolQuery = prepareWhereClause(collectionDetailsRequest); if (DASHBOARD_GROUPING_BILLCOLLECTORWISE.equalsIgnoreCase(collectionDetailsRequest.getType())) groupingField = "billCollector"; else if (DASHBOARD_GROUPING_REVENUEINSPECTORWISE.equalsIgnoreCase(collectionDetailsRequest.getType())) groupingField = "revenueInspector"; else if (DASHBOARD_GROUPING_REVENUEOFFICERWISE.equalsIgnoreCase(collectionDetailsRequest.getType())) groupingField = "revenueOfficer"; if (StringUtils.isNotBlank(groupingField)) boolQuery = boolQuery.mustNot(QueryBuilders.matchQuery(groupingField, StringUtils.EMPTY)); SearchQuery searchQueryColl = new NativeSearchQueryBuilder().withIndices(COLLECTION_ACHIEVEMENTS_INDEX_NAME) .withQuery(boolQuery).withSort(new FieldSortBuilder("achievement").order(SortOrder.DESC)) .withPageable(new PageRequest(0, 3000)) .addAggregation(AggregationBuilders.terms(BY_AGGREGATION_FIELD).field(groupingField).size(3000)) .build(); List<CollectionAchievementsIndex> achievementsList = elasticsearchTemplate.queryForList(searchQueryColl, CollectionAchievementsIndex.class); for (CollectionAchievementsIndex achievement : achievementsList) { taxPayerDetails = new TaxPayerDetails(); setAchieversData(collectionDetailsRequest, taxPayerDetails, achievement); taxPayerDetailsList.add(taxPayerDetails); } //Sort the final list based on the achievements, in desc and asc order to get the top 10 and bottom 10 achievers respectively List<TaxPayerDetails> topTenList = new ArrayList(taxPayerDetailsList); if (!topTenList.isEmpty()) Collections.sort(topTenList, (detail1, detail2) -> detail2.getAchievement().compareTo(detail1.getAchievement())); rankingsMap.put("topTenRankings", topTenList.subList(0, topTenList.size() < 10 ? topTenList.size() : 10)); List<TaxPayerDetails> bottomTenList = new ArrayList(taxPayerDetailsList); if (!bottomTenList.isEmpty()) Collections.sort(bottomTenList, (detail1, detail2) -> detail1.getAchievement().compareTo(detail2.getAchievement())); rankingsMap.put("bottomTenRankings", bottomTenList.subList(0, bottomTenList.size() < 10 ? bottomTenList.size() : 10)); return rankingsMap; } private void setAchieversData(CollectionDetailsRequest collectionDetailsRequest, TaxPayerDetails taxPayerDetails, CollectionAchievementsIndex achievement) { taxPayerDetails.setRegionName(achievement.getRegionName()); taxPayerDetails.setDistrictName(achievement.getDistrictName()); taxPayerDetails.setUlbGrade(achievement.getCityGrade()); taxPayerDetails.setUlbName(achievement.getCityName()); taxPayerDetails.setUlbCode(achievement.getCityCode()); if (DASHBOARD_GROUPING_BILLCOLLECTORWISE.equalsIgnoreCase(collectionDetailsRequest.getType())) { taxPayerDetails.setBillCollector(achievement.getBillCollector()); taxPayerDetails.setBillCollMobNo(achievement.getBillCollectorMobileNo()); taxPayerDetails.setBillCollectorCode(achievement.getBillCollectorCode()); } else if (DASHBOARD_GROUPING_REVENUEINSPECTORWISE.equalsIgnoreCase(collectionDetailsRequest.getType())) { taxPayerDetails.setRevenueInspector(achievement.getRevenueInspector()); taxPayerDetails.setRevInspectorMobNo(achievement.getRevenueInspectorMobileNo()); taxPayerDetails.setRevenueInspectorCode(achievement.getRevenueInspectorCode()); } else if (DASHBOARD_GROUPING_REVENUEOFFICERWISE.equalsIgnoreCase(collectionDetailsRequest.getType())) { taxPayerDetails.setRevenueOfficer(achievement.getRevenueOfficer()); taxPayerDetails.setRevOfficerMobNo(achievement.getRevenueOfficerMobileNo()); taxPayerDetails.setRevenueOfficerCode(achievement.getRevenueOfficerCode()); } taxPayerDetails.setTotalDmd(BigDecimal.valueOf(achievement.getTotalDemand())); taxPayerDetails.setCytdDmd(BigDecimal.valueOf(achievement.getCytdDemand())); taxPayerDetails.setCytdColl(BigDecimal.valueOf(achievement.getCytdColl())); taxPayerDetails.setCytdBalDmd(BigDecimal.valueOf(achievement.getCytdBalDemand())); taxPayerDetails.setAchievement(BigDecimal.valueOf(achievement.getAchievement())); taxPayerDetails.setLytdColl(BigDecimal.valueOf(achievement.getLytdColl())); taxPayerDetails.setLyVar(BigDecimal.valueOf(achievement.getLyVar())); } /** * Returns List of Top Ten Tax Performers * * @param collectionDetailsRequest * @return */ public TaxPayerResponseDetails getTopTenTaxPerformers(final CollectionDetailsRequest collectionDetailsRequest, CFinancialYear currFinYear, boolean isForRanking) { final TaxPayerResponseDetails topTaxPerformers = new TaxPayerResponseDetails(); List<TaxPayerDetails> taxProducers; List<TaxPayerDetails> taxAchievers; if (StringUtils.isNotBlank(collectionDetailsRequest.getType()) && (collectionDetailsRequest.getType() .equalsIgnoreCase(PropertyTaxConstants.DASHBOARD_GROUPING_BILLCOLLECTORWISE) || DASHBOARD_GROUPING_REVENUEINSPECTORWISE.equalsIgnoreCase(collectionDetailsRequest.getType()) || DASHBOARD_GROUPING_REVENUEOFFICERWISE.equalsIgnoreCase(collectionDetailsRequest.getType()))) { // Fetch the ward wise data for the filters final List<TaxPayerDetails> wardWiseTaxProducers = returnUlbWiseAggregationResults( collectionDetailsRequest, PROPERTY_TAX_INDEX_NAME, false, TOTAL_COLLECTION, 250, true, currFinYear); final Map<String, TaxPayerDetails> wardWiseTaxPayersDetails = new HashMap<>(); final Map<String, List<TaxPayerDetails>> billCollectorWiseMap = new LinkedHashMap<>(); final List<TaxPayerDetails> taxPayerDetailsList = new ArrayList<>(); final List<TaxPayerDetails> billCollectorWiseTaxPayerDetails = new ArrayList<>(); // Get ward wise tax payers details prepareWardWiseTaxPayerDetails(wardWiseTaxProducers, wardWiseTaxPayersDetails); // Group the revenue ward details by bill collector prepareBillCollectorWiseMapData(collectionDetailsRequest, wardWiseTaxPayersDetails, billCollectorWiseMap, taxPayerDetailsList); // Prepare Bill Collector wise tax payers details prepareTaxersInfoForBillCollectors(collectionDetailsRequest, billCollectorWiseMap, billCollectorWiseTaxPayerDetails); taxProducers = getTaxPayersForBillCollector(false, billCollectorWiseTaxPayerDetails, true, isForRanking); taxAchievers = getTaxPayersForBillCollector(false, billCollectorWiseTaxPayerDetails, false, isForRanking); } else { taxProducers = returnUlbWiseAggregationResults(collectionDetailsRequest, PROPERTY_TAX_INDEX_NAME, false, TOTAL_COLLECTION, 10, false, currFinYear); taxAchievers = returnUlbWiseAggregationResults(collectionDetailsRequest, PROPERTY_TAX_INDEX_NAME, false, TOTAL_COLLECTION, 120, false, currFinYear); } topTaxPerformers.setProducers(taxProducers); topTaxPerformers.setAchievers(taxAchievers); return topTaxPerformers; } /** * Returns List of Bottom Ten Tax Performers * * @param collectionDetailsRequest * @return */ public TaxPayerResponseDetails getBottomTenTaxPerformers( final CollectionDetailsRequest collectionDetailsRequest, CFinancialYear currFinYear, boolean isForRanking) { final TaxPayerResponseDetails topTaxPerformers = new TaxPayerResponseDetails(); List<TaxPayerDetails> taxProducers; List<TaxPayerDetails> taxAchievers; if (StringUtils.isNotBlank(collectionDetailsRequest.getType()) && (collectionDetailsRequest.getType() .equalsIgnoreCase(PropertyTaxConstants.DASHBOARD_GROUPING_BILLCOLLECTORWISE) || DASHBOARD_GROUPING_REVENUEINSPECTORWISE.equalsIgnoreCase(collectionDetailsRequest.getType()) || DASHBOARD_GROUPING_REVENUEOFFICERWISE.equalsIgnoreCase(collectionDetailsRequest.getType()))) { final List<TaxPayerDetails> wardWiseTaxProducers = returnUlbWiseAggregationResults( collectionDetailsRequest, PROPERTY_TAX_INDEX_NAME, false, TOTAL_COLLECTION, 250, true, currFinYear); final Map<String, TaxPayerDetails> wardWiseTaxPayersDetails = new HashMap<>(); final Map<String, List<TaxPayerDetails>> billCollectorWiseMap = new LinkedHashMap<>(); final List<TaxPayerDetails> taxPayerDetailsList = new ArrayList<>(); final List<TaxPayerDetails> billCollectorWiseTaxPayerDetails = new ArrayList<>(); // Get ward wise tax payers details prepareWardWiseTaxPayerDetails(wardWiseTaxProducers, wardWiseTaxPayersDetails); // Group the revenue ward details by bill collector prepareBillCollectorWiseMapData(collectionDetailsRequest, wardWiseTaxPayersDetails, billCollectorWiseMap, taxPayerDetailsList); // Prepare Bill Collector wise tax payers details prepareTaxersInfoForBillCollectors(collectionDetailsRequest, billCollectorWiseMap, billCollectorWiseTaxPayerDetails); taxProducers = getTaxPayersForBillCollector(true, billCollectorWiseTaxPayerDetails, true, isForRanking); taxAchievers = getTaxPayersForBillCollector(true, billCollectorWiseTaxPayerDetails, false, isForRanking); } else { taxProducers = returnUlbWiseAggregationResults(collectionDetailsRequest, PROPERTY_TAX_INDEX_NAME, true, TOTAL_COLLECTION, 10, false, currFinYear); taxAchievers = returnUlbWiseAggregationResults(collectionDetailsRequest, PROPERTY_TAX_INDEX_NAME, true, TOTAL_COLLECTION, 120, false, currFinYear); } topTaxPerformers.setProducers(taxProducers); topTaxPerformers.setAchievers(taxAchievers); return topTaxPerformers; } /** * Returns Top Ten with ULB wise grouping and total amount aggregation * * @param collectionDetailsRequest * @param indexName * @param order * @param orderingAggregationName * @return */ public List<TaxPayerDetails> returnUlbWiseAggregationResults( final CollectionDetailsRequest collectionDetailsRequest, final String indexName, final Boolean order, final String orderingAggregationName, final int size, final boolean isBillCollectorWise, CFinancialYear currFinYear) { BigDecimal proportionalArrearDmd; BigDecimal proportionalCurrDmd; BigDecimal variation; Sum totalDemandAggregation; Sum totalCollectionAggregation; Sum arrearDmd; Sum currentDmd; Sum arrearInterestDmd; Sum currentInterestDmd; Sum arrearCollAmt; Sum currentCollAmt; Sum arrearIntColl; Sum currentIntColl; final List<TaxPayerDetails> taxPayers = new ArrayList<>(); Map<String, BillCollectorIndex> wardWiseBillCollectors = new HashMap<>(); final BoolQueryBuilder boolQuery = prepareWhereClause(collectionDetailsRequest) .filter(QueryBuilders.matchQuery(IS_ACTIVE, true)) .filter(QueryBuilders.matchQuery(IS_EXEMPTED, false)); // orderingAggregationName is the aggregation name by which we have to // order the results // IN this case can be one of "totaldemand" or "total_collection" or // "avg_achievement" String groupingField; if (StringUtils.isNotBlank(collectionDetailsRequest.getUlbCode()) || StringUtils .isNotBlank(collectionDetailsRequest.getType()) && (DASHBOARD_GROUPING_WARDWISE.equalsIgnoreCase(collectionDetailsRequest.getType()) || DASHBOARD_GROUPING_BILLCOLLECTORWISE.equalsIgnoreCase(collectionDetailsRequest.getType()) || DASHBOARD_GROUPING_REVENUEINSPECTORWISE .equalsIgnoreCase(collectionDetailsRequest.getType()) || DASHBOARD_GROUPING_REVENUEOFFICERWISE .equalsIgnoreCase(collectionDetailsRequest.getType()))) groupingField = REVENUE_WARD; else groupingField = CITY_NAME; AggregationBuilder aggregation; SearchQuery searchQueryColl; // Apply the ordering and max results size only if the type is not // billcollector if (!isBillCollectorWise) { aggregation = prepareAggregationForTaxPayers(size, groupingField) .order(Terms.Order.aggregation(orderingAggregationName, order)); searchQueryColl = new NativeSearchQueryBuilder().withIndices(indexName).withQuery(boolQuery) .addAggregation(aggregation).build(); } else { aggregation = prepareAggregationForTaxPayers(250, groupingField); searchQueryColl = new NativeSearchQueryBuilder().withIndices(indexName).withQuery(boolQuery) .withPageable(new PageRequest(0, 250)).addAggregation(aggregation).build(); } final Aggregations collAggr = elasticsearchTemplate.query(searchQueryColl, response -> response.getAggregations()); final Date fromDate = DateUtils.startOfDay(currFinYear.getStartingDate()); final Date toDate = org.apache.commons.lang3.time.DateUtils.addDays(new Date(), 1); final Date lastYearFromDate = org.apache.commons.lang3.time.DateUtils.addYears(fromDate, -1); final Date lastYearToDate = org.apache.commons.lang3.time.DateUtils.addYears(toDate, -1); // Fetch ward wise Bill Collector details for ward based grouping if (DASHBOARD_GROUPING_WARDWISE.equalsIgnoreCase(collectionDetailsRequest.getType())) wardWiseBillCollectors = collectionIndexElasticSearchService .getWardWiseBillCollectors(collectionDetailsRequest); TaxPayerDetails taxDetail; final StringTerms totalAmountAggr = collAggr.get(BY_AGGREGATION_FIELD); BigDecimal lastYearCollection; for (final Terms.Bucket entry : totalAmountAggr.getBuckets()) { taxDetail = new TaxPayerDetails(); taxDetail.setRegionName(collectionDetailsRequest.getRegionName()); taxDetail.setDistrictName(collectionDetailsRequest.getDistrictName()); taxDetail.setUlbGrade(collectionDetailsRequest.getUlbGrade()); final String fieldName = String.valueOf(entry.getKey()); // If the grouping is based on ward, set the Bill Collector name and number if (groupingField.equals(REVENUE_WARD)) { taxDetail.setWardName(fieldName); if (DASHBOARD_GROUPING_WARDWISE.equalsIgnoreCase(collectionDetailsRequest.getType()) && !wardWiseBillCollectors.isEmpty()) { taxDetail.setBillCollector(wardWiseBillCollectors.get(fieldName) == null ? StringUtils.EMPTY : wardWiseBillCollectors.get(fieldName).getBillCollector()); taxDetail.setBillCollMobNo(wardWiseBillCollectors.get(fieldName) == null ? StringUtils.EMPTY : wardWiseBillCollectors.get(fieldName).getBillCollectorMobileNo()); taxDetail.setBillCollectorCode(wardWiseBillCollectors.get(fieldName) == null ? StringUtils.EMPTY : wardWiseBillCollectors.get(fieldName).getBillCollectorCode()); } } else taxDetail.setUlbName(fieldName); // Proportional Demand = (totalDemand/12)*noOfmonths final int noOfMonths = DateUtils.noOfMonthsBetween(fromDate, toDate) + 1; totalDemandAggregation = entry.getAggregations().get(TOTALDEMAND); totalCollectionAggregation = entry.getAggregations().get(TOTAL_COLLECTION); arrearDmd = entry.getAggregations().get(ARREAR_DMD_STR); currentDmd = entry.getAggregations().get(CURR_DMD); arrearInterestDmd = entry.getAggregations().get(ARREAR_INTEREST_DMD); currentInterestDmd = entry.getAggregations().get(CURR_INTEREST_DMD); arrearCollAmt = entry.getAggregations().get(ARREAR_COLLECTION); currentCollAmt = entry.getAggregations().get(ANNUAL_COLLECTION); arrearIntColl = entry.getAggregations().get(ARREAR_INTEREST_COLLECTION); currentIntColl = entry.getAggregations().get(CURRENT_INTEREST_COLLECTION); final BigDecimal totalDemandValue = BigDecimal.valueOf(totalDemandAggregation.getValue()).setScale(0, BigDecimal.ROUND_HALF_UP); final BigDecimal totalCollections = BigDecimal.valueOf(totalCollectionAggregation.getValue()) .setScale(0, BigDecimal.ROUND_HALF_UP); final BigDecimal proportionalDemand = totalDemandValue .divide(BigDecimal.valueOf(12), BigDecimal.ROUND_HALF_UP) .multiply(BigDecimal.valueOf(noOfMonths)); taxDetail.setTotalDmd(totalDemandValue); taxDetail.setCytdColl(totalCollections); taxDetail.setCytdDmd(proportionalDemand); if (proportionalDemand.compareTo(BigDecimal.ZERO) > 0) taxDetail.setAchievement(totalCollections.multiply(BIGDECIMAL_100).divide(proportionalDemand, 1, BigDecimal.ROUND_HALF_UP)); taxDetail.setCytdBalDmd(proportionalDemand.subtract(totalCollections)); if (StringUtils.isNotBlank(taxDetail.getUlbName())) lastYearCollection = collectionIndexElasticSearchService.getCollectionBetweenDates( collectionDetailsRequest, lastYearFromDate, lastYearToDate, fieldName, null, "totalAmount"); else lastYearCollection = collectionIndexElasticSearchService.getCollectionBetweenDates( collectionDetailsRequest, lastYearFromDate, lastYearToDate, null, fieldName, "totalAmount"); taxDetail.setLytdColl(lastYearCollection); taxDetail.setArrearColl( BigDecimal.valueOf(arrearCollAmt.getValue()).setScale(0, BigDecimal.ROUND_HALF_UP)); taxDetail.setCurrentColl( BigDecimal.valueOf(currentCollAmt.getValue()).setScale(0, BigDecimal.ROUND_HALF_UP)); taxDetail.setInterestColl( BigDecimal.valueOf(arrearIntColl.getValue()).setScale(0, BigDecimal.ROUND_HALF_UP).add( BigDecimal.valueOf(currentIntColl.getValue()).setScale(0, BigDecimal.ROUND_HALF_UP))); taxDetail.setArrearDemand( BigDecimal.valueOf(arrearDmd.getValue()).setScale(0, BigDecimal.ROUND_HALF_UP)); taxDetail.setCurrentDemand( BigDecimal.valueOf(currentDmd.getValue()).setScale(0, BigDecimal.ROUND_HALF_UP)); taxDetail.setArrearInterestDemand( BigDecimal.valueOf(arrearInterestDmd.getValue()).setScale(0, BigDecimal.ROUND_HALF_UP)); taxDetail.setCurrentInterestDemand( BigDecimal.valueOf(currentInterestDmd.getValue()).setScale(0, BigDecimal.ROUND_HALF_UP)); proportionalArrearDmd = taxDetail.getArrearDemand() .divide(BigDecimal.valueOf(12), BigDecimal.ROUND_HALF_UP) .multiply(BigDecimal.valueOf(noOfMonths)); proportionalCurrDmd = taxDetail.getCurrentDemand() .divide(BigDecimal.valueOf(12), BigDecimal.ROUND_HALF_UP) .multiply(BigDecimal.valueOf(noOfMonths)); taxDetail.setProportionalArrearDemand(proportionalArrearDmd); taxDetail.setProportionalCurrentDemand(proportionalCurrDmd); // variance = ((currentYearCollection - // lastYearCollection)*100)/lastYearCollection if (lastYearCollection.compareTo(BigDecimal.ZERO) == 0) variation = BIGDECIMAL_100; else variation = totalCollections.subtract(lastYearCollection).multiply(BIGDECIMAL_100) .divide(lastYearCollection, 1, BigDecimal.ROUND_HALF_UP); taxDetail.setLyVar(variation); taxPayers.add(taxDetail); } // If for Bill Collector, then fetch details for all wards, else limit // the results size if (isBillCollectorWise) return taxPayers; else return returnTopResults(taxPayers, size, order); } private TermsBuilder prepareAggregationForTaxPayers(final int size, final String groupingField) { return AggregationBuilders.terms(BY_AGGREGATION_FIELD).field(groupingField).size(size) .subAggregation(AggregationBuilders.sum(TOTALDEMAND).field(TOTAL_DEMAND)) .subAggregation(AggregationBuilders.sum(TOTAL_COLLECTION).field("totalCollection")) .subAggregation(AggregationBuilders.sum(ARREAR_COLLECTION).field(ARREAR_COLLECTION)) .subAggregation(AggregationBuilders.sum(ANNUAL_COLLECTION).field(ANNUAL_COLLECTION)) .subAggregation( AggregationBuilders.sum(ARREAR_INTEREST_COLLECTION).field(ARREAR_INTEREST_COLLECTION)) .subAggregation( AggregationBuilders.sum(CURRENT_INTEREST_COLLECTION).field(CURRENT_INTEREST_COLLECTION)) .subAggregation(AggregationBuilders.sum(ARREAR_DMD_STR).field(ARREAR_DEMAND)) .subAggregation(AggregationBuilders.sum(CURR_DMD).field("annualDemand")) .subAggregation(AggregationBuilders.sum(ARREAR_INTEREST_DMD).field("arrearInterestDemand")) .subAggregation(AggregationBuilders.sum(CURR_INTEREST_DMD).field("currentInterestDemand")); } private List<TaxPayerDetails> returnTopResults(final List<TaxPayerDetails> taxPayers, final int size, final Boolean order) { if (size > 10) { if (order) Collections.sort(taxPayers); else Collections.sort(taxPayers, Collections.reverseOrder()); return taxPayers.subList(0, taxPayers.size() < 10 ? taxPayers.size() : 10); } return taxPayers; } /** * Returns top 100 tax defaulters * * @param propertyTaxDefaultersRequest * @return */ public List<TaxDefaulters> getTopDefaulters(final PropertyTaxDefaultersRequest propertyTaxDefaultersRequest) { BoolQueryBuilder boolQuery = filterBasedOnRequest(propertyTaxDefaultersRequest); boolQuery = boolQuery.filter(QueryBuilders.matchQuery(IS_ACTIVE, true)) .filter(QueryBuilders.matchQuery(IS_EXEMPTED, false)); final SearchQuery searchQuery = new NativeSearchQueryBuilder().withIndices(PROPERTY_TAX_INDEX_NAME) .withQuery(boolQuery).withSort(new FieldSortBuilder("totalBalance").order(SortOrder.DESC)) .withPageable(new PageRequest(0, 100)).build(); final Page<PropertyTaxIndex> propertyTaxRecords = elasticsearchTemplate.queryForPage(searchQuery, PropertyTaxIndex.class); final List<TaxDefaulters> taxDefaulters = new ArrayList<>(); TaxDefaulters taxDefaulter; for (final PropertyTaxIndex property : propertyTaxRecords) { taxDefaulter = new TaxDefaulters(); taxDefaulter.setOwnerName(property.getConsumerName()); taxDefaulter.setPropertyType(property.getConsumerType()); taxDefaulter.setUlbName(property.getCityName()); taxDefaulter.setBalance(BigDecimal.valueOf(property.getTotalBalance())); taxDefaulter.setPeriod( StringUtils.isBlank(property.getDuePeriod()) ? StringUtils.EMPTY : property.getDuePeriod()); taxDefaulters.add(taxDefaulter); } return taxDefaulters; } /** * This is used for top 100 defaulter's since ward level filtering is also present Query which filters documents from index * based on request * * @param propertyTaxDefaultersRequest * @return */ private BoolQueryBuilder filterBasedOnRequest(final PropertyTaxDefaultersRequest propertyTaxDefaultersRequest) { BoolQueryBuilder boolQuery = QueryBuilders.boolQuery() .filter(QueryBuilders.rangeQuery(TOTAL_DEMAND).from(0).to(null)); if (StringUtils.isNotBlank(propertyTaxDefaultersRequest.getRegionName())) boolQuery = boolQuery .filter(QueryBuilders.matchQuery(REGION_NAME, propertyTaxDefaultersRequest.getRegionName())); if (StringUtils.isNotBlank(propertyTaxDefaultersRequest.getDistrictName())) boolQuery = boolQuery.filter( QueryBuilders.matchQuery(DISTRICT_NAME, propertyTaxDefaultersRequest.getDistrictName())); if (StringUtils.isNotBlank(propertyTaxDefaultersRequest.getUlbCode())) boolQuery = boolQuery .filter(QueryBuilders.matchQuery(CITY_CODE, propertyTaxDefaultersRequest.getUlbCode())); if (StringUtils.isNotBlank(propertyTaxDefaultersRequest.getUlbGrade())) boolQuery = boolQuery .filter(QueryBuilders.matchQuery(CITY_GRADE, propertyTaxDefaultersRequest.getUlbGrade())); if (StringUtils.isNotBlank(propertyTaxDefaultersRequest.getWardName())) boolQuery = boolQuery .filter(QueryBuilders.matchQuery(REVENUE_WARD, propertyTaxDefaultersRequest.getWardName())); if (StringUtils.isNotBlank(propertyTaxDefaultersRequest.getType())) if (propertyTaxDefaultersRequest.getType().equalsIgnoreCase(DASHBOARD_GROUPING_REGIONWISE) && StringUtils.isNotBlank(propertyTaxDefaultersRequest.getRegionName())) boolQuery = boolQuery.filter( QueryBuilders.matchQuery(REGION_NAME, propertyTaxDefaultersRequest.getRegionName())); else if (propertyTaxDefaultersRequest.getType().equalsIgnoreCase(DASHBOARD_GROUPING_DISTRICTWISE) && StringUtils.isNotBlank(propertyTaxDefaultersRequest.getDistrictName())) boolQuery = boolQuery.filter( QueryBuilders.matchQuery(DISTRICT_NAME, propertyTaxDefaultersRequest.getDistrictName())); else if (propertyTaxDefaultersRequest.getType().equalsIgnoreCase(DASHBOARD_GROUPING_CITYWISE) && StringUtils.isNotBlank(propertyTaxDefaultersRequest.getUlbCode())) boolQuery = boolQuery .filter(QueryBuilders.matchQuery(CITY_CODE, propertyTaxDefaultersRequest.getUlbCode())); else if (propertyTaxDefaultersRequest.getType().equalsIgnoreCase(DASHBOARD_GROUPING_GRADEWISE) && StringUtils.isNotBlank(propertyTaxDefaultersRequest.getUlbGrade())) boolQuery = boolQuery .filter(QueryBuilders.matchQuery(CITY_GRADE, propertyTaxDefaultersRequest.getUlbGrade())); return boolQuery; } /** * Builds query based on the input parameters sent * * @param collectionDetailsRequest * @param indexName * @param ulbCodeField * @return BoolQueryBuilder */ private BoolQueryBuilder prepareWhereClause(final CollectionDetailsRequest collectionDetailsRequest) { BoolQueryBuilder boolQuery = QueryBuilders.boolQuery() .filter(QueryBuilders.rangeQuery(TOTAL_DEMAND).from(0).to(null)); if (StringUtils.isNotBlank(collectionDetailsRequest.getRegionName())) boolQuery = boolQuery .filter(QueryBuilders.matchQuery(REGION_NAME, collectionDetailsRequest.getRegionName())); if (StringUtils.isNotBlank(collectionDetailsRequest.getDistrictName())) boolQuery = boolQuery .filter(QueryBuilders.matchQuery(DISTRICT_NAME, collectionDetailsRequest.getDistrictName())); if (StringUtils.isNotBlank(collectionDetailsRequest.getUlbGrade())) boolQuery = boolQuery .filter(QueryBuilders.matchQuery(CITY_GRADE, collectionDetailsRequest.getUlbGrade())); if (StringUtils.isNotBlank(collectionDetailsRequest.getUlbCode())) boolQuery = boolQuery .filter(QueryBuilders.matchQuery(CITY_CODE, collectionDetailsRequest.getUlbCode())); if (StringUtils.isNotBlank(collectionDetailsRequest.getPropertyType())) boolQuery = collectionIndexElasticSearchService.queryForPropertyType(collectionDetailsRequest, boolQuery, PROPERTY_TAX_INDEX_NAME); return boolQuery; } /** * Prepare ward wise tax payers details - Map of ward name and tax payers bean * * @param wardWiseTaxProducers * @param wardWiseTaxPayersDetails */ private void prepareWardWiseTaxPayerDetails(final List<TaxPayerDetails> wardWiseTaxProducers, final Map<String, TaxPayerDetails> wardWiseTaxPayersDetails) { for (final TaxPayerDetails taxPayers : wardWiseTaxProducers) wardWiseTaxPayersDetails.put(taxPayers.getWardName(), taxPayers); } /** * Prepare a Map of Bill Collector names and the tax payers list for their respective wards * * @param collectionDetailsRequest * @param wardWiseTaxPayersDetails * @param billCollectorWiseMap * @param taxPayerDetailsList */ private void prepareBillCollectorWiseMapData(final CollectionDetailsRequest collectionDetailsRequest, final Map<String, TaxPayerDetails> wardWiseTaxPayersDetails, final Map<String, List<TaxPayerDetails>> billCollectorWiseMap, List<TaxPayerDetails> taxPayerDetailsList) { String userNameAndNumber = StringUtils.EMPTY; final List<BillCollectorIndex> billCollectorsList = collectionIndexElasticSearchService .getBillCollectorDetails(collectionDetailsRequest); for (final BillCollectorIndex billCollIndex : billCollectorsList) if (wardWiseTaxPayersDetails.get(billCollIndex.getRevenueWard()) != null && StringUtils.isNotBlank(billCollIndex.getRevenueWard())) { if (DASHBOARD_GROUPING_BILLCOLLECTORWISE.equalsIgnoreCase(collectionDetailsRequest.getType())) userNameAndNumber = billCollIndex.getBillCollector().concat("~") .concat(StringUtils.isBlank(billCollIndex.getBillCollectorMobileNo()) ? StringUtils.EMPTY : billCollIndex.getBillCollectorMobileNo()) .concat("~").concat(billCollIndex.getBillCollectorCode()); else if (DASHBOARD_GROUPING_REVENUEINSPECTORWISE .equalsIgnoreCase(collectionDetailsRequest.getType())) userNameAndNumber = billCollIndex.getRevenueInspector().concat("~") .concat(StringUtils.isBlank(billCollIndex.getRevenueInspectorMobileNo()) ? StringUtils.EMPTY : billCollIndex.getRevenueInspectorMobileNo()) .concat("~").concat(billCollIndex.getRevenueInspectorCode()); else if (DASHBOARD_GROUPING_REVENUEOFFICERWISE.equalsIgnoreCase(collectionDetailsRequest.getType())) userNameAndNumber = billCollIndex.getRevenueOfficer().concat("~") .concat(StringUtils.isBlank(billCollIndex.getRevenueOfficerMobileNo()) ? StringUtils.EMPTY : billCollIndex.getRevenueOfficerMobileNo()) .concat("~").concat(billCollIndex.getRevenueOfficerCode()); if (billCollectorWiseMap.isEmpty()) { taxPayerDetailsList.add(wardWiseTaxPayersDetails.get(billCollIndex.getRevenueWard())); billCollectorWiseMap.put(userNameAndNumber, taxPayerDetailsList); } else if (!billCollectorWiseMap.containsKey(userNameAndNumber)) { taxPayerDetailsList = new ArrayList<>(); taxPayerDetailsList.add(wardWiseTaxPayersDetails.get(billCollIndex.getRevenueWard())); billCollectorWiseMap.put(userNameAndNumber, taxPayerDetailsList); } else billCollectorWiseMap.get(userNameAndNumber) .add(wardWiseTaxPayersDetails.get(billCollIndex.getRevenueWard())); } } /** * Prepares the Producers and Acheivers list - Bill Collector wise * * @param collectionDetailsRequest * @param order * @param wardWiseTaxProducers * @param billCollectorWiseTaxPayerDetails * @param isForProducers * @return */ private List<TaxPayerDetails> getTaxPayersForBillCollector(final boolean order, final List<TaxPayerDetails> billCollectorWiseTaxPayerDetails, final boolean isForProducers, boolean isForRanking) { final Map<BigDecimal, TaxPayerDetails> sortedTaxersMap = new HashMap<>(); // For propducers, prepare sorted list of totalCollection // For achievers, prepare sorted list of achievement if (isForProducers) for (final TaxPayerDetails payerDetails : billCollectorWiseTaxPayerDetails) sortedTaxersMap.put(payerDetails.getCytdColl(), payerDetails); else for (final TaxPayerDetails payerDetails : billCollectorWiseTaxPayerDetails) sortedTaxersMap.put(payerDetails.getAchievement(), payerDetails); final List<BigDecimal> sortedList = new ArrayList<>(sortedTaxersMap.keySet()); // Decides whether API should return in ascending or descending order if (order) Collections.sort(sortedList); else Collections.sort(sortedList, Collections.reverseOrder()); final List<TaxPayerDetails> taxersResult = new ArrayList<>(); for (final BigDecimal amount : sortedList) taxersResult.add(sortedTaxersMap.get(amount)); if (!isForRanking && taxersResult.size() > 10) return taxersResult.subList(0, taxersResult.size() < 10 ? taxersResult.size() : 10); else return taxersResult; } /** * Prepare list of TaxPayerDetails for each bill collector by summing up the values in each ward for the respective bil * collector * * @param collectionDetailsRequest * @param billCollectorWiseMap * @param billCollectorWiseTaxPayerDetails */ private void prepareTaxersInfoForBillCollectors(final CollectionDetailsRequest collectionDetailsRequest, final Map<String, List<TaxPayerDetails>> billCollectorWiseMap, final List<TaxPayerDetails> billCollectorWiseTaxPayerDetails) { BigDecimal cytdColl; BigDecimal lytdColl; BigDecimal cytdDmd; BigDecimal totalDmd; TaxPayerDetails taxPayerDetails; String[] userNameNumberArr; for (final Entry<String, List<TaxPayerDetails>> entry : billCollectorWiseMap.entrySet()) { taxPayerDetails = new TaxPayerDetails(); cytdColl = BigDecimal.ZERO; lytdColl = BigDecimal.ZERO; cytdDmd = BigDecimal.ZERO; totalDmd = BigDecimal.ZERO; userNameNumberArr = entry.getKey().split("~"); for (final TaxPayerDetails taxPayer : entry.getValue()) { totalDmd = totalDmd.add(taxPayer.getTotalDmd() == null ? BigDecimal.ZERO : taxPayer.getTotalDmd()); cytdColl = cytdColl.add(taxPayer.getCytdColl() == null ? BigDecimal.ZERO : taxPayer.getCytdColl()); cytdDmd = cytdDmd.add(taxPayer.getCytdDmd() == null ? BigDecimal.ZERO : taxPayer.getCytdDmd()); lytdColl = lytdColl.add(taxPayer.getLytdColl() == null ? BigDecimal.ZERO : taxPayer.getLytdColl()); } if (DASHBOARD_GROUPING_BILLCOLLECTORWISE.equalsIgnoreCase(collectionDetailsRequest.getType())) { taxPayerDetails .setBillCollector(userNameNumberArr.length > 0 ? userNameNumberArr[0] : StringUtils.EMPTY); taxPayerDetails .setBillCollMobNo(userNameNumberArr.length > 1 ? userNameNumberArr[1] : StringUtils.EMPTY); taxPayerDetails.setBillCollectorCode( userNameNumberArr.length > 2 ? userNameNumberArr[2] : StringUtils.EMPTY); } else if (DASHBOARD_GROUPING_REVENUEINSPECTORWISE .equalsIgnoreCase(collectionDetailsRequest.getType())) { taxPayerDetails.setRevenueInspector( userNameNumberArr.length > 0 ? userNameNumberArr[0] : StringUtils.EMPTY); taxPayerDetails.setRevInspectorMobNo( userNameNumberArr.length > 1 ? userNameNumberArr[1] : StringUtils.EMPTY); taxPayerDetails.setRevenueInspectorCode( userNameNumberArr.length > 2 ? userNameNumberArr[2] : StringUtils.EMPTY); } else if (DASHBOARD_GROUPING_REVENUEOFFICERWISE.equalsIgnoreCase(collectionDetailsRequest.getType())) { taxPayerDetails .setRevenueOfficer(userNameNumberArr.length > 0 ? userNameNumberArr[0] : StringUtils.EMPTY); taxPayerDetails.setRevOfficerMobNo( userNameNumberArr.length > 1 ? userNameNumberArr[1] : StringUtils.EMPTY); taxPayerDetails.setRevenueOfficerCode( userNameNumberArr.length > 2 ? userNameNumberArr[2] : StringUtils.EMPTY); } taxPayerDetails.setRegionName(collectionDetailsRequest.getRegionName()); taxPayerDetails.setDistrictName(collectionDetailsRequest.getDistrictName()); taxPayerDetails.setUlbGrade(collectionDetailsRequest.getUlbGrade()); taxPayerDetails.setCytdColl(cytdColl); taxPayerDetails.setCytdDmd(cytdDmd); taxPayerDetails.setCytdBalDmd(cytdDmd.subtract(cytdColl)); taxPayerDetails.setTotalDmd(totalDmd); taxPayerDetails.setLytdColl(lytdColl); if (cytdDmd.compareTo(BigDecimal.ZERO) > 0) taxPayerDetails.setAchievement( cytdColl.multiply(BIGDECIMAL_100).divide(cytdDmd, 1, BigDecimal.ROUND_HALF_UP)); if (lytdColl.compareTo(BigDecimal.ZERO) == 0) taxPayerDetails.setLyVar(BIGDECIMAL_100); else taxPayerDetails.setLyVar(cytdColl.subtract(lytdColl).multiply(BIGDECIMAL_100).divide(lytdColl, 1, BigDecimal.ROUND_HALF_UP)); billCollectorWiseTaxPayerDetails.add(taxPayerDetails); } } /** * Prepares DCB Details * @param individualDmdDetails * @param demandDivisionMap */ private void prepareDCBDetailsMap(final StringTerms individualDmdDetails, final Map<String, Map<String, BigDecimal>> demandDivisionMap) { Map<String, BigDecimal> individualDmdMap; Sum arrearDmd; Sum currentDmd; Sum arrearInterestDmd; Sum currentInterestDmd; Sum totalDmd; Sum adjustment; Sum arrearColl; Sum currentColl; Sum arrearInterestColl; Sum currentInterestColl; Sum advanceColl; Sum rebate; Sum totalColl; if (individualDmdDetails != null) for (final Terms.Bucket entry : individualDmdDetails.getBuckets()) { individualDmdMap = new HashMap<>(); arrearDmd = entry.getAggregations().get(ARREAR_DMD_STR); currentDmd = entry.getAggregations().get(CURR_DMD); arrearInterestDmd = entry.getAggregations().get(ARREAR_INTEREST_DMD); currentInterestDmd = entry.getAggregations().get(CURR_INTEREST_DMD); totalDmd = entry.getAggregations().get("total_dmd"); adjustment = entry.getAggregations().get("adjustment"); arrearColl = entry.getAggregations().get("arrear_coll"); currentColl = entry.getAggregations().get("curr_coll"); arrearInterestColl = entry.getAggregations().get("arrear_interest_coll"); currentInterestColl = entry.getAggregations().get("curr_interest_coll"); advanceColl = entry.getAggregations().get("advance"); rebate = entry.getAggregations().get(REBATE_STR); totalColl = entry.getAggregations().get("total_coll"); individualDmdMap.put(ARREAR_DMD, BigDecimal.valueOf(arrearDmd.getValue()).setScale(0, BigDecimal.ROUND_HALF_UP)); individualDmdMap.put(CURRENT_DMD, BigDecimal.valueOf(currentDmd.getValue()).setScale(0, BigDecimal.ROUND_HALF_UP)); individualDmdMap.put(ARREAR_INT_DMD, BigDecimal.valueOf(arrearInterestDmd.getValue()).setScale(0, BigDecimal.ROUND_HALF_UP)); individualDmdMap.put(CURRENT_INT_DMD, BigDecimal.valueOf(currentInterestDmd.getValue()).setScale(0, BigDecimal.ROUND_HALF_UP)); individualDmdMap.put(TOTAL_DMD_STR, BigDecimal.valueOf(totalDmd.getValue()).setScale(0, BigDecimal.ROUND_HALF_UP)); individualDmdMap.put("adjustment", BigDecimal.valueOf(adjustment.getValue()).setScale(0, BigDecimal.ROUND_HALF_UP)); individualDmdMap.put(ARREAR_COLL_STR, BigDecimal.valueOf(arrearColl.getValue()).setScale(0, BigDecimal.ROUND_HALF_UP)); individualDmdMap.put(CURRENT_COLL_STR, BigDecimal.valueOf(currentColl.getValue()).setScale(0, BigDecimal.ROUND_HALF_UP)); individualDmdMap.put(ARREAR_INT_COLL, BigDecimal.valueOf(arrearInterestColl.getValue()).setScale(0, BigDecimal.ROUND_HALF_UP)); individualDmdMap.put(CURRENT_INT_COLL, BigDecimal.valueOf(currentInterestColl.getValue()).setScale(0, BigDecimal.ROUND_HALF_UP)); individualDmdMap.put(ADVANCE_COLL_STR, BigDecimal.valueOf(advanceColl.getValue()).setScale(0, BigDecimal.ROUND_HALF_UP)); individualDmdMap.put(REBATE_STR, BigDecimal.valueOf(rebate.getValue()).setScale(0, BigDecimal.ROUND_HALF_UP)); individualDmdMap.put(TOTAL_COLL_STR, BigDecimal.valueOf(totalColl.getValue()).setScale(0, BigDecimal.ROUND_HALF_UP)); demandDivisionMap.put(String.valueOf(entry.getKey()), individualDmdMap); } } /** * Provides citywise DCB details * @param collectionDetailsRequest * @return list */ public List<DCBDetails> getDCBDetails(final CollectionDetailsRequest collectionDetailsRequest) { final List<DCBDetails> dcbDetailsList = new ArrayList<>(); DCBDetails dCBDetails; String name; final Map<String, Map<String, BigDecimal>> demandDivisionMap = new HashMap<>(); final Map<String, BigDecimal> assessmentsCountMap = collectionIndexElasticSearchService .getCollectionAndDemandCountResults(collectionDetailsRequest, null, null, PROPERTY_TAX_INDEX_NAME, "consumerCode", CITY_NAME); final StringTerms individualDmdDetails = collectionIndexElasticSearchService .getIndividualDemands(collectionDetailsRequest, PROPERTY_TAX_INDEX_NAME, CITY_NAME, true); prepareDCBDetailsMap(individualDmdDetails, demandDivisionMap); for (final Map.Entry<String, Map<String, BigDecimal>> entry : demandDivisionMap.entrySet()) { dCBDetails = new DCBDetails(); name = entry.getKey(); dCBDetails.setBoundaryName(name); if (!assessmentsCountMap.isEmpty() && assessmentsCountMap.get(name) != null) dCBDetails.setTotalAssessments( assessmentsCountMap.get(name) == null ? BigDecimal.ZERO : assessmentsCountMap.get(name)); dCBDetails.setArrearDemand(demandDivisionMap.get(name).get(ARREAR_DMD) == null ? BigDecimal.ZERO : demandDivisionMap.get(name).get(ARREAR_DMD)); dCBDetails.setArrearPenalty(demandDivisionMap.get(name).get(ARREAR_INT_DMD) == null ? BigDecimal.ZERO : demandDivisionMap.get(name).get(ARREAR_INT_DMD)); dCBDetails.setCurrentDemand(demandDivisionMap.get(name).get(CURRENT_DMD) == null ? BigDecimal.ZERO : demandDivisionMap.get(name).get(CURRENT_DMD)); dCBDetails.setCurrentPenalty(demandDivisionMap.get(name).get(CURRENT_INT_DMD) == null ? BigDecimal.ZERO : demandDivisionMap.get(name).get(CURRENT_INT_DMD)); dCBDetails.setTotalDemand(demandDivisionMap.get(name).get(TOTAL_DMD_STR) == null ? BigDecimal.ZERO : demandDivisionMap.get(name).get(TOTAL_DMD_STR)); dCBDetails.setAdjustment(BigDecimal.ZERO); dCBDetails.setArrearColl(demandDivisionMap.get(name).get(ARREAR_COLL_STR) == null ? BigDecimal.ZERO : demandDivisionMap.get(name).get(ARREAR_COLL_STR)); dCBDetails.setCurrentColl(demandDivisionMap.get(name).get(CURRENT_COLL_STR) == null ? BigDecimal.ZERO : demandDivisionMap.get(name).get(CURRENT_COLL_STR)); dCBDetails .setArrearPenaltyColl(demandDivisionMap.get(name).get(ARREAR_INT_COLL) == null ? BigDecimal.ZERO : demandDivisionMap.get(name).get(ARREAR_INT_COLL)); dCBDetails.setCurrentPenaltyColl( demandDivisionMap.get(name).get(CURRENT_INT_COLL) == null ? BigDecimal.ZERO : demandDivisionMap.get(name).get(CURRENT_INT_COLL)); dCBDetails.setAdvanceColl(demandDivisionMap.get(name).get(ADVANCE_COLL_STR) == null ? BigDecimal.ZERO : demandDivisionMap.get(name).get(ADVANCE_COLL_STR)); dCBDetails.setRebate(demandDivisionMap.get(name).get(REBATE_STR) == null ? BigDecimal.ZERO : demandDivisionMap.get(name).get(REBATE_STR)); dCBDetails.setTotalColl(demandDivisionMap.get(name).get(TOTAL_COLL_STR) == null ? BigDecimal.ZERO : demandDivisionMap.get(name).get(TOTAL_COLL_STR)); if (dCBDetails.getTotalDemand().compareTo(BigDecimal.ZERO) > 0) dCBDetails.setPercentage(dCBDetails.getTotalColl().multiply(BIGDECIMAL_100) .divide(dCBDetails.getTotalDemand(), BigDecimal.ROUND_HALF_EVEN)); dcbDetailsList.add(dCBDetails); } return dcbDetailsList; } public List<DemandVariance> prepareDemandVariationDetails(CollectionDetailsRequest collectionDetailsRequest) { DemandVariance demandDetails = new DemandVariance(); final List<DemandVariance> demandVarianceList = new ArrayList<>(); DemandVariationDetails demandVariationDetails; boolean exists; /** * To prepare details of primary demand */ Aggregations aggr = getDemandVarianceAggregations(true, collectionDetailsRequest); StringTerms wards = aggr.get(BY_TYPE); for (final Terms.Bucket entry : wards.getBuckets()) { demandDetails = new DemandVariance(); demandDetails.setName(entry.getKeyAsString()); demandVariationDetails = new DemandVariationDetails(); demandVariationDetails.setApplicationType(PRIMARY_DEMAND); demandVariationDetails.setTotalApplication(entry.getDocCount()); populateDemandInfo(demandVariationDetails, entry); demandDetails.setPrimary(demandVariationDetails); demandVarianceList.add(demandDetails); } /** * To prepare details of demands for different application types */ aggr = getDemandVarianceAggregations(false, collectionDetailsRequest); wards = aggr.get(BY_TYPE); for (final Terms.Bucket entry : wards.getBuckets()) { exists = false; for (final DemandVariance demandVariance : demandVarianceList) if (entry.getKeyAsString().equals(demandVariance.getName())) { demandDetails = demandVariance; exists = true; break; } if (!exists) { demandDetails = new DemandVariance(); demandDetails.setName(entry.getKeyAsString()); } setDemandsForApplicationTypes(demandDetails, entry); if (!exists) demandVarianceList.add(demandDetails); } return demandVarianceList; } private void setDemandsForApplicationTypes(final DemandVariance demandDetails, final Terms.Bucket entry) { DemandVariationDetails demandVariationDetails; final StringTerms appType = entry.getAggregations().get(BY_APPLICATION); for (final Terms.Bucket appBucket : appType.getBuckets()) { demandVariationDetails = new DemandVariationDetails(); if (PT_NEW_ASSMNT.equals(appBucket.getKeyAsString())) { populateDataForApplicationTypes(demandVariationDetails, appBucket); demandDetails.setNewAssessment(demandVariationDetails); } else if (PT_ALTER_ASSMNT.equals(appBucket.getKeyAsString())) { populateDataForApplicationTypes(demandVariationDetails, appBucket); demandDetails.setAdditionAlteration(demandVariationDetails); } } } private void populateDataForApplicationTypes(final DemandVariationDetails demandVariationDetails, final Terms.Bucket entry) { demandVariationDetails.setApplicationType(entry.getKeyAsString()); demandVariationDetails.setTotalApplication(entry.getDocCount()); populateDemandInfo(demandVariationDetails, entry); } private void populateDemandInfo(final DemandVariationDetails demandVariationDetails, final Terms.Bucket entry) { Sum sum = entry.getAggregations().get(ARREAR_DEMAND); Double demand = sum.getValue(); demandVariationDetails.setArrearDemand(demand); sum = entry.getAggregations().get(CURRENT_DEMAND); demand = sum.getValue(); demandVariationDetails.setCurrentDemand(demand); sum = entry.getAggregations().get(TOTAL_DEMAND); demand = sum.getValue(); demandVariationDetails.setTotalDemand(demand); } public Aggregations getDemandVarianceAggregations(final Boolean isprimaryDemand, CollectionDetailsRequest collectionDetailsRequest) { AggregationBuilder aggregation; BoolQueryBuilder boolQuery = filterByTypeForAggregation(collectionDetailsRequest); final CFinancialYear financialYear = cFinancialYearService.getFinancialYearByDate(new Date()); String aggregationField = StringUtils.EMPTY; if (StringUtils.isNotBlank(collectionDetailsRequest.getType())) { aggregationField = collectionIndexElasticSearchService.getAggregrationField(collectionDetailsRequest); } if (!isprimaryDemand) { boolQuery = boolQuery.filter(QueryBuilders.rangeQuery(DEMAND_DATE) .gte(DATEFORMATTER_YYYY_MM_DD.format(financialYear.getStartingDate())) .lte(DATEFORMATTER_YYYY_MM_DD.format(financialYear.getEndingDate())).includeUpper(false)); aggregation = AggregationBuilders.terms(BY_TYPE).field(aggregationField) .subAggregation(AggregationBuilders.terms(BY_APPLICATION).field(APPLICATION_TYPE) .subAggregation(AggregationBuilders.sum(ARREAR_DEMAND).field(ARREAR_DEMAND)) .subAggregation(AggregationBuilders.sum(CURRENT_DEMAND).field(CURRENT_DEMAND)) .subAggregation(AggregationBuilders.sum(TOTAL_DEMAND).field(TOTAL_DEMAND))) .size(250); } else { boolQuery = boolQuery.filter(QueryBuilders.rangeQuery(DEMAND_DATE) .lt(DATEFORMATTER_YYYY_MM_DD.format(financialYear.getStartingDate())).includeUpper(false)); aggregation = AggregationBuilders.terms(BY_TYPE).field(aggregationField) .subAggregation(AggregationBuilders.sum(ARREAR_DEMAND).field(ARREAR_DEMAND)) .subAggregation(AggregationBuilders.sum(CURRENT_DEMAND).field(CURRENT_DEMAND)) .subAggregation(AggregationBuilders.sum(TOTAL_DEMAND).field(TOTAL_DEMAND)).size(250); } final SearchQuery searchQueryColl = new NativeSearchQueryBuilder().withIndices(DEMAND_VARIATION) .withQuery(boolQuery).addAggregation(aggregation).build(); return elasticsearchTemplate.query(searchQueryColl, response -> response.getAggregations()); } private BoolQueryBuilder filterByTypeForAggregation(CollectionDetailsRequest collectionDetailsRequest) { BoolQueryBuilder boolQuery = new BoolQueryBuilder(); if (DASHBOARD_GROUPING_WARDWISE.equalsIgnoreCase(collectionDetailsRequest.getType())) boolQuery = boolQuery.must(QueryBuilders.matchQuery(CITY_CODE, collectionDetailsRequest.getUlbCode())); return boolQuery; } }