diff --git a/business-services/billing-service/src/main/java/org/egov/demand/config/ApplicationProperties.java b/business-services/billing-service/src/main/java/org/egov/demand/config/ApplicationProperties.java index 3ea2daee2..e70212df5 100644 --- a/business-services/billing-service/src/main/java/org/egov/demand/config/ApplicationProperties.java +++ b/business-services/billing-service/src/main/java/org/egov/demand/config/ApplicationProperties.java @@ -120,10 +120,12 @@ public class ApplicationProperties { @Value("${kafka.topics.receipt.cancel.name}") private String receiptCancellationTopic; - @Value("${kafka.topics.demand.index.name}") - private String demandIndexTopic; - - + @Value("${kafka.topics.create.demand.index.name}") + private String createDemandIndexTopic; + + @Value("${kafka.topics.update.demand.index.name}") + private String updateDemandIndexTopic; + /* * billing service v1.1 */ @@ -207,4 +209,14 @@ public class ApplicationProperties { @Value("${kafka.mgramseva.update.bill}") private String updateBill; + + @Value("${egov.demand.default.offset}") + private Integer demandDefaultOffset; + + @Value("${egov.demand.default.limit}") + private Integer demandDefaultLimit; + + @Value("${egov.demand.max.limit}") + private Integer demandMaxLimit; + } diff --git a/business-services/billing-service/src/main/java/org/egov/demand/model/AggregatedDemandDetailResponse.java b/business-services/billing-service/src/main/java/org/egov/demand/model/AggregatedDemandDetailResponse.java index 1feca1ce4..523548b53 100644 --- a/business-services/billing-service/src/main/java/org/egov/demand/model/AggregatedDemandDetailResponse.java +++ b/business-services/billing-service/src/main/java/org/egov/demand/model/AggregatedDemandDetailResponse.java @@ -38,4 +38,8 @@ public class AggregatedDemandDetailResponse { private BigDecimal netDueWithPenalty; private BigDecimal totalApplicablePenalty; + + private long latestDemandCreatedTime; + + private long latestDemandPenaltyCreatedtime; } \ No newline at end of file diff --git a/business-services/billing-service/src/main/java/org/egov/demand/model/DemandCriteria.java b/business-services/billing-service/src/main/java/org/egov/demand/model/DemandCriteria.java index 1dfff60a5..8781713e5 100644 --- a/business-services/billing-service/src/main/java/org/egov/demand/model/DemandCriteria.java +++ b/business-services/billing-service/src/main/java/org/egov/demand/model/DemandCriteria.java @@ -76,6 +76,10 @@ public class DemandCriteria { private Long periodFrom; private Long periodTo; + + private Long fromDate; + + private Long toDate; private Type type; @@ -86,7 +90,11 @@ public class DemandCriteria { private String status; private Boolean isPaymentCompleted; - + + private Integer offset; + + private Integer limit; + @Default private Boolean receiptRequired=false; } diff --git a/business-services/billing-service/src/main/java/org/egov/demand/repository/DemandRepository.java b/business-services/billing-service/src/main/java/org/egov/demand/repository/DemandRepository.java index aaff916e4..cacd7b296 100644 --- a/business-services/billing-service/src/main/java/org/egov/demand/repository/DemandRepository.java +++ b/business-services/billing-service/src/main/java/org/egov/demand/repository/DemandRepository.java @@ -49,6 +49,7 @@ import java.util.UUID; import java.util.stream.Collectors; +import org.apache.kafka.common.protocol.types.Field; import org.egov.demand.model.AuditDetails; import org.egov.demand.model.Demand; import org.egov.demand.model.DemandCriteria; @@ -59,15 +60,18 @@ import org.egov.demand.repository.rowmapper.DemandRowMapper; import org.egov.demand.util.Util; import org.egov.demand.web.contract.DemandRequest; +import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.BatchPreparedStatementSetter; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.PreparedStatementSetter; +import org.springframework.jdbc.core.SingleColumnRowMapper; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; import lombok.extern.slf4j.Slf4j; +import org.springframework.util.CollectionUtils; @Repository @Slf4j @@ -409,4 +413,24 @@ public List getDemandHistory(DemandCriteria demandCriteria) { String searchDemandQuery = demandQueryBuilder.getDemandHistoryQuery(demandCriteria, preparedStatementValues); return jdbcTemplate.query(searchDemandQuery, preparedStatementValues.toArray(), demandHistoryRowMapper); } + + public List getDemandIds(DemandCriteria demandCriteria) + { + List preparedStmtList = new ArrayList<>(); + String searchDemandQuery = demandQueryBuilder.getdemandIdSearchQuery(demandCriteria, preparedStmtList); + return jdbcTemplate.query(searchDemandQuery, new SingleColumnRowMapper<>(String.class), preparedStmtList.toArray()); + } + + public List getDemandsPlainSearch(DemandCriteria demandCriteria) { + + if (demandCriteria.getDemandId() == null || CollectionUtils.isEmpty(demandCriteria.getDemandId())) + throw new CustomException("PLAIN_SEARCH_ERROR", "Search only allowed by ids!"); + + List preparedStmtList = new ArrayList<>(); + String query = demandQueryBuilder.getDemandPlainSearchQuery(demandCriteria, preparedStmtList); + log.info("Query: " + query); + log.info("PS: " + preparedStmtList); + return jdbcTemplate.query(query, preparedStmtList.toArray(), demandRowMapper); + } + } diff --git a/business-services/billing-service/src/main/java/org/egov/demand/repository/querybuilder/DemandQueryBuilder.java b/business-services/billing-service/src/main/java/org/egov/demand/repository/querybuilder/DemandQueryBuilder.java index 3c0c39a2c..70c551954 100644 --- a/business-services/billing-service/src/main/java/org/egov/demand/repository/querybuilder/DemandQueryBuilder.java +++ b/business-services/billing-service/src/main/java/org/egov/demand/repository/querybuilder/DemandQueryBuilder.java @@ -39,12 +39,10 @@ */ package org.egov.demand.repository.querybuilder; -import java.util.Collection; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; -import java.util.Set; +import org.apache.kafka.common.protocol.types.Field; import org.egov.demand.model.DemandCriteria; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; @@ -136,7 +134,8 @@ public class DemandQueryBuilder { public static final String DEMAND_UPDATE_CONSUMERCODE_QUERY="UPDATE egbs_demand_v1 SET consumercode=?, lastmodifiedby=?, lastmodifiedtime=? " + " WHERE tenantid=? AND id IN ("; - + + public static final String FETCH_DEMAND_IDS_QUERY = "SELECT dmd.id AS did FROM egbs_demand_v1 dmd WHERE"; public String getDemandQueryForConsumerCodes(Map> businessConsumercodeMap,List preparedStmtList, String tenantId){ @@ -174,9 +173,43 @@ public String getDemandQuery(DemandCriteria demandCriteria, List prepare StringBuilder demandQuery = new StringBuilder(BASE_DEMAND_QUERY); + addDemandCriteria(demandQuery, demandCriteria, preparedStatementValues); + addOrderByClause(demandQuery, DEMAND_QUERY_ORDER_BY_CLAUSE); + addPagingClause(demandQuery, preparedStatementValues); + + log.info("the query String for demand : " + demandQuery.toString()); + return demandQuery.toString(); + } + + public String getdemandIdSearchQuery(DemandCriteria demandCriteria, List preparedStatementValues) + { + StringBuilder demandIdSearchQuery = new StringBuilder(FETCH_DEMAND_IDS_QUERY); + addDemandCriteria(demandIdSearchQuery, demandCriteria, preparedStatementValues); + addOrderByClause(demandIdSearchQuery, DEMAND_QUERY_ORDER_BY_CLAUSE); + addPagingClauseForDemandIdSearch(demandIdSearchQuery, demandCriteria, preparedStatementValues); + log.info("Query for demand id search : " + demandIdSearchQuery.toString()); + return demandIdSearchQuery.toString(); + + } + + public String getDemandPlainSearchQuery(DemandCriteria demandCriteria, List preparedStmtList) { + + StringBuilder demandQuery = new StringBuilder(BASE_DEMAND_QUERY); + + Set ids = demandCriteria.getDemandId(); + if (!CollectionUtils.isEmpty(ids)) { + demandQuery.append(" dmd.id IN (").append(createQuery( new ArrayList<>(ids))).append(")"); + addToPreparedStatement(preparedStmtList, ids); + } + + return demandQuery.toString(); + } + + public void addDemandCriteria(StringBuilder demandQuery, DemandCriteria demandCriteria, List preparedStatementValues) + { String tenantId = demandCriteria.getTenantId(); String[] tenantIdChunks = tenantId.split("\\."); - + if(tenantIdChunks.length == 1){ demandQuery.append(" dmd.tenantid LIKE ? "); preparedStatementValues.add(demandCriteria.getTenantId() + '%'); @@ -184,7 +217,7 @@ public String getDemandQuery(DemandCriteria demandCriteria, List prepare demandQuery.append(" dmd.tenantid = ? "); preparedStatementValues.add(demandCriteria.getTenantId()); } - + if (demandCriteria.getStatus() != null) { @@ -192,7 +225,7 @@ public String getDemandQuery(DemandCriteria demandCriteria, List prepare demandQuery.append("dmd.status=?"); preparedStatementValues.add(demandCriteria.getStatus()); } - + if (demandCriteria.getDemandId() != null && !demandCriteria.getDemandId().isEmpty()) { addAndClause(demandQuery); demandQuery.append("dmd.id IN (" + getIdQueryForStrings(demandCriteria.getDemandId()) + ")"); @@ -208,39 +241,45 @@ public String getDemandQuery(DemandCriteria demandCriteria, List prepare demandQuery.append("dmd.businessservice=?"); preparedStatementValues.add(demandCriteria.getBusinessService()); } - + if(demandCriteria.getIsPaymentCompleted() != null){ addAndClause(demandQuery); demandQuery.append("dmd.ispaymentcompleted = ?"); preparedStatementValues.add(demandCriteria.getIsPaymentCompleted()); } - + if (demandCriteria.getPeriodFrom() != null) { addAndClause(demandQuery); demandQuery.append("dmd.taxPeriodFrom >= ?"); preparedStatementValues.add(demandCriteria.getPeriodFrom()); } - + if(demandCriteria.getPeriodTo() != null){ addAndClause(demandQuery); demandQuery.append("dmd.taxPeriodTo <= ?"); preparedStatementValues.add(demandCriteria.getPeriodTo()); } - + + if(demandCriteria.getFromDate() != null){ + addAndClause(demandQuery); + demandQuery.append(" dmd.createdtime >= ? "); + preparedStatementValues.add(demandCriteria.getFromDate()); + } + + if(demandCriteria.getToDate() != null){ + addAndClause(demandQuery); + demandQuery.append(" dmd.createdtime <= ? "); + preparedStatementValues.add(demandCriteria.getToDate()); + } + if (demandCriteria.getConsumerCode() != null && !demandCriteria.getConsumerCode().isEmpty()) { addAndClause(demandQuery); demandQuery.append("dmd.consumercode IN (" - + getIdQueryForStrings(demandCriteria.getConsumerCode()) + ")"); + + getIdQueryForStrings(demandCriteria.getConsumerCode()) + ")"); addToPreparedStatement(preparedStatementValues, demandCriteria.getConsumerCode()); } - - addOrderByClause(demandQuery, DEMAND_QUERY_ORDER_BY_CLAUSE); - addPagingClause(demandQuery, preparedStatementValues); - - log.info("the query String for demand : " + demandQuery.toString()); - return demandQuery.toString(); } - + private static void addOrderByClause(StringBuilder demandQueryBuilder,String columnName) { demandQueryBuilder.append(" ORDER BY " + columnName); } @@ -256,7 +295,7 @@ private static boolean addAndClause(StringBuilder queryString) { queryString.append(" AND "); return true; } - + private static String getIdQueryForStrings(Set idList) { StringBuilder builder = new StringBuilder(); @@ -272,11 +311,11 @@ private void addToPreparedStatement(List preparedStmtList, Collection{ preparedStmtList.add(id);}); } - + public String getDemandHistoryQuery(DemandCriteria demandCriteria, List preparedStatementValues) { - StringBuilder demandQuery = new StringBuilder(BASE_DEMAND_HISTORY_QUERY); - + StringBuilder demandQuery = new StringBuilder(BASE_DEMAND_HISTORY_QUERY); + if( demandCriteria.getTenantId() != null) { demandQuery.append(" dmd.tenantid = ? "); preparedStatementValues.add(demandCriteria.getTenantId()); @@ -286,11 +325,11 @@ public String getDemandHistoryQuery(DemandCriteria demandCriteria, List demandQuery.append("dmd.businessservice=?"); preparedStatementValues.add(demandCriteria.getBusinessService()); } - + if (demandCriteria.getConsumerCode() != null && !demandCriteria.getConsumerCode().isEmpty()) { addAndClause(demandQuery); demandQuery.append("dmd.consumercode IN (" - + getIdQueryForStrings(demandCriteria.getConsumerCode()) + ")"); + + getIdQueryForStrings(demandCriteria.getConsumerCode()) + ")"); addToPreparedStatement(preparedStatementValues, demandCriteria.getConsumerCode()); } @@ -299,4 +338,22 @@ public String getDemandHistoryQuery(DemandCriteria demandCriteria, List log.info("the query String for demand : " + demandQuery.toString()); return demandQuery.toString(); } + + private static void addPagingClauseForDemandIdSearch(StringBuilder demandQuery, DemandCriteria demandCriteria, List preparedStatementValues) { + demandQuery.append(" LIMIT ?"); + preparedStatementValues.add(demandCriteria.getLimit()); + demandQuery.append(" OFFSET ?"); + preparedStatementValues.add(demandCriteria.getOffset()); + } + + private Object createQuery(List ids) { + StringBuilder builder = new StringBuilder(); + int length = ids.size(); + for (int i = 0; i < length; i++) { + builder.append(" ?"); + if (i != length - 1) + builder.append(","); + } + return builder.toString(); + } } diff --git a/business-services/billing-service/src/main/java/org/egov/demand/service/DemandService.java b/business-services/billing-service/src/main/java/org/egov/demand/service/DemandService.java index 49b795ca4..acc049f64 100644 --- a/business-services/billing-service/src/main/java/org/egov/demand/service/DemandService.java +++ b/business-services/billing-service/src/main/java/org/egov/demand/service/DemandService.java @@ -56,6 +56,7 @@ import org.egov.demand.config.ApplicationProperties; import org.egov.demand.model.*; import org.egov.demand.model.BillV2.BillStatus; +import org.egov.demand.producer.Producer; import org.egov.demand.repository.AmendmentRepository; import org.egov.demand.repository.BillRepositoryV2; import org.egov.demand.repository.DemandRepository; @@ -120,6 +121,9 @@ public class DemandService { @Autowired private DemandValidatorV1 demandValidatorV1; + + @Autowired + private Producer producer; /** * Method to create new demand @@ -287,6 +291,24 @@ public DemandResponse updateAsync(DemandRequest demandRequest, PaymentBackUpdate return new DemandResponse(responseInfoFactory.getResponseInfo(requestInfo, HttpStatus.CREATED), demands); } + public List demandPlainSearch(DemandCriteria demandCriteria, RequestInfo requestInfo) + { + if (demandCriteria.getLimit() != null && demandCriteria.getLimit() > applicationProperties.getDemandMaxLimit()) + demandCriteria.setLimit(applicationProperties.getDemandMaxLimit()); + + Set demandIds = null; + + if(demandCriteria.getDemandId() != null && !CollectionUtils.isEmpty(demandCriteria.getDemandId())) + demandIds = demandCriteria.getDemandId(); + else + demandIds = new HashSet<>(demandRepository.getDemandIds(demandCriteria)); + + if(demandIds.isEmpty()) + return Collections.emptyList(); + + DemandCriteria demandSearchCriteria = DemandCriteria.builder().demandId(demandIds).build(); + return demandRepository.getDemandsPlainSearch(demandSearchCriteria); + } /** * Search method to fetch demands from DB @@ -358,10 +380,12 @@ public List getDemands(DemandCriteria demandCriteria, RequestInfo reques public void save(DemandRequest demandRequest) { demandRepository.save(demandRequest); + producer.push(applicationProperties.getCreateDemandIndexTopic(), demandRequest); } public void update(DemandRequest demandRequest, PaymentBackUpdateAudit paymentBackUpdateAudit) { demandRepository.update(demandRequest, paymentBackUpdateAudit); + producer.push(applicationProperties.getUpdateDemandIndexTopic(), demandRequest); } @@ -547,6 +571,9 @@ public DemandHistory getDemandHistory(@Valid DemandCriteria demandCriteria, Requ public AggregatedDemandDetailResponse getAllDemands(DemandCriteria demandCriteria, RequestInfo requestInfo) { //demandValidatorV1.validateDemandCriteria(demandCriteria, requestInfo); + long latestDemandCreatedTime = 0l; + + long latestDemandPenaltyCreatedtime=0l; UserSearchRequest userSearchRequest = null; List payers = null; @@ -594,6 +621,46 @@ public AggregatedDemandDetailResponse getAllDemands(DemandCriteria demandCriteri }).collect(Collectors.toList()); List>> demandDetailsList = new ArrayList<>(); + List demandsTogetDemandGeneratedDate= demands; + + // Filter demands where demandDetails have taxHeadMasterCode as 10101 + List filteredDemands = demandsTogetDemandGeneratedDate.stream() + .filter(demand -> demand.getDemandDetails().stream() + .anyMatch(detail -> "10101".equals(detail.getTaxHeadMasterCode()))) + .collect(Collectors.toList()); + + Collections.sort(filteredDemands, new Comparator() { + @Override + public int compare(Demand d1, Demand d2) { + return Long.compare(d2.getTaxPeriodFrom(), d1.getTaxPeriodFrom()); + } + }); + + + + if (!filteredDemands.isEmpty()) { + Demand latestDemand = filteredDemands.get(0); + + Optional detail10101 = latestDemand.getDemandDetails().stream() + .filter(detail -> "10101".equals(detail.getTaxHeadMasterCode())) + .findFirst(); + + Optional detailWSTimePenalty = latestDemand.getDemandDetails().stream() + .filter(detail -> "WS_TIME_PENALTY".equals(detail.getTaxHeadMasterCode())) + .findFirst(); + + if (detail10101.isPresent()) { + latestDemandCreatedTime = detail10101.get().getAuditDetails().getCreatedTime(); + } + + if (detailWSTimePenalty.isPresent()) { + latestDemandPenaltyCreatedtime = detailWSTimePenalty.get().getAuditDetails().getCreatedTime(); + } + } else { + log.info("No demands found with taxHeadMasterCode 10101 or WS_TIME_PENALTY."); + } + + for (Demand demand : demands) { log.info("Inside demand"); Map> demandMap = new HashMap<>(); @@ -748,7 +815,9 @@ public AggregatedDemandDetailResponse getAllDemands(DemandCriteria demandCriteri .advanceAdjusted(advanceAdjusted) .advanceAvailable(advanceAvailable) .remainingAdvance(remainingAdvance) - .totalApplicablePenalty(totalApplicablePenalty).build(); + .totalApplicablePenalty(totalApplicablePenalty) + .latestDemandCreatedTime(latestDemandCreatedTime) + .latestDemandPenaltyCreatedtime(latestDemandPenaltyCreatedtime).build(); return aggregatedDemandDetailResponse; diff --git a/business-services/billing-service/src/main/java/org/egov/demand/web/controller/DemandController.java b/business-services/billing-service/src/main/java/org/egov/demand/web/controller/DemandController.java index e5a61433d..9807b15b8 100644 --- a/business-services/billing-service/src/main/java/org/egov/demand/web/controller/DemandController.java +++ b/business-services/billing-service/src/main/java/org/egov/demand/web/controller/DemandController.java @@ -62,14 +62,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import lombok.extern.slf4j.Slf4j; @@ -172,4 +165,17 @@ public ResponseEntity getAggregatedDemandDetails(@RequestBody RequestInfoWrap AggregatedDemandDetailResponse demands = demandService.getAllDemands(demandCriteria, requestInfo); return new ResponseEntity<>(demands, HttpStatus.OK); } + + @PostMapping("/_plainsearch") + public ResponseEntity plainsearch(@RequestBody RequestInfoWrapper requestInfoWrapper, + @ModelAttribute @Valid DemandCriteria demandCriteria) { + + RequestInfo requestInfo = requestInfoWrapper.getRequestInfo(); + List demands = demandService.demandPlainSearch(demandCriteria, requestInfo); + DemandResponse response = DemandResponse.builder().demands(demands) + .responseInfo(responseFactory.getResponseInfo(requestInfo, HttpStatus.OK)).build(); + return new ResponseEntity<>(response, HttpStatus.OK); + + } + } \ No newline at end of file diff --git a/business-services/billing-service/src/main/resources/application.properties b/business-services/billing-service/src/main/resources/application.properties index d5c30b522..67bcdd3e9 100644 --- a/business-services/billing-service/src/main/resources/application.properties +++ b/business-services/billing-service/src/main/resources/application.properties @@ -49,7 +49,8 @@ kafka.topics.receipt.cancel.name=egov.collection.receipt-cancel kafka.topics.receipt.cancel.key=receipt-cancel #Indexer topics -kafka.topics.demand.index.name=create-demand-index-v1 +kafka.topics.create.demand.index.name=create-demand-index +kafka.topics.update.demand.index.name=update-demand-index # KAFKA CONSUMER CONFIGURATIONS @@ -100,6 +101,12 @@ bs.demanddetail.seq.name=seq_egbs_demanddetail bs.demand.audit.seq.name=seq_egbs_demand_audit bs.demanddetail.audit.seq.name=seq_egbs_demanddetail_audit +# Pagination Details +#Pagination +egov.demand.default.offset=0 +egov.demand.default.limit=10 +egov.demand.max.limit=1000 + #billing-service1.1 # localization url diff --git a/business-services/billing-service/src/main/resources/db/migration/main/V20221206104420__egbs_bill_alter_add_consumercode.sql b/business-services/billing-service/src/main/resources/db/migration/main/V20221206104422__egbs_bill_alter_add_consumercode.sql similarity index 98% rename from business-services/billing-service/src/main/resources/db/migration/main/V20221206104420__egbs_bill_alter_add_consumercode.sql rename to business-services/billing-service/src/main/resources/db/migration/main/V20221206104422__egbs_bill_alter_add_consumercode.sql index 4c2c308e6..4ccd414c4 100644 --- a/business-services/billing-service/src/main/resources/db/migration/main/V20221206104420__egbs_bill_alter_add_consumercode.sql +++ b/business-services/billing-service/src/main/resources/db/migration/main/V20221206104422__egbs_bill_alter_add_consumercode.sql @@ -1,6 +1,6 @@ ALTER TABLE egbs_bill_v1 ADD COLUMN IF NOT EXISTS consumercode CHARACTER VARYING(256); -UPDATE egbs_bill_v1 b SET consumerCode = bd.consumercode FROM egbs_billdetail_v1 bd WHERE bd.billid = b.id and b.consumercode is null ; +UPDATE egbs_bill_v1 b SET consumerCode = bd.consumercode FROM egbs_billdetail_v1 bd WHERE bd.billid = b.id and b.consumercode is null; ALTER TABLE egbs_bill_v1 ALTER COLUMN consumercode SET NOT NULL; diff --git a/business-services/egov-hrms/src/main/java/org/egov/hrms/config/PropertiesManager.java b/business-services/egov-hrms/src/main/java/org/egov/hrms/config/PropertiesManager.java index 3b04dd0f8..e9adc7abb 100644 --- a/business-services/egov-hrms/src/main/java/org/egov/hrms/config/PropertiesManager.java +++ b/business-services/egov-hrms/src/main/java/org/egov/hrms/config/PropertiesManager.java @@ -91,7 +91,7 @@ public class PropertiesManager { //Kafka Topics @Value("${kafka.topics.save.service}") public String saveEmployeeTopic; - + @Value("${kafka.topics.update.service}") public String UpdateEmployeeTopic; @@ -100,7 +100,12 @@ public class PropertiesManager { @Value("${kafka.topics.hrms.updateData}") public String updateTopic; - + + @Value("${kafka.topics.save.service.index}") + public String saveEmployeeIndexTopic; + + @Value("${kafka.topics.update.service.index}") + public String UpdateEmployeeIndexTopic; //Variables @Value("${egov.idgen.ack.name}") @@ -117,4 +122,7 @@ public class PropertiesManager { @Value("${sms.user.creation.enabled}") public boolean isSMSForUserCreationEnable; + + @Value("${egov.hrms.max.pagination.limit}") + public Integer hrmsMaxLimit; } \ No newline at end of file diff --git a/business-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeQueries.java b/business-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeQueries.java index 9bb07130f..f04a84080 100644 --- a/business-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeQueries.java +++ b/business-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeQueries.java @@ -52,4 +52,8 @@ public class EmployeeQueries { public static final String HRMS_GET_ASSIGNMENT = "select distinct(employeeid) from eg_hrms_assignment assignment where assignment.tenantid notnull "; public static final String HRMS_COUNT_EMP_QUERY = "SELECT active, count(*) FROM eg_hrms_employee WHERE tenantid "; + + public static final String HRMS_GET_EMP_IDS_QUERY = "SELECT employee.uuid FROM eg_hrms_employee employee WHERE"; + + public static final String HRMS_QUERY_ORDER_BY_CLAUSE = "employee.createddate"; } diff --git a/business-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeQueryBuilder.java b/business-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeQueryBuilder.java index 67140d47e..8812b302b 100644 --- a/business-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeQueryBuilder.java +++ b/business-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeQueryBuilder.java @@ -2,6 +2,7 @@ import org.apache.commons.lang3.StringUtils; import org.egov.hrms.config.PropertiesManager; +import org.egov.hrms.web.contract.EmployeePlainSearchCriteria; import org.egov.hrms.web.contract.EmployeeSearchCriteria; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -13,6 +14,8 @@ import java.util.Set; import java.util.stream.Collectors; +import static org.egov.hrms.repository.EmployeeQueries.HRMS_QUERY_ORDER_BY_CLAUSE; + @Service public class EmployeeQueryBuilder { @@ -158,5 +161,75 @@ private void addToPreparedStatement(List preparedStmtList, List ids) }); } + /** + * Returns query for searching employee ids based on criteria + * + * @param criteria + * @return + */ + public String getEmployeeIdsQuery(EmployeePlainSearchCriteria criteria, List preparedStmtList ) { + StringBuilder builder = new StringBuilder(EmployeeQueries.HRMS_GET_EMP_IDS_QUERY); + + if(!StringUtils.isEmpty(criteria.getTenantId())) { + if (criteria.getTenantId().equalsIgnoreCase(properties.getStateLevelTenantId())) { + builder.append(" employee.tenantid LIKE ? "); + preparedStmtList.add('%' + criteria.getTenantId() + '%'); + } else { + builder.append(" employee.tenantid = ? "); + preparedStmtList.add(criteria.getTenantId()); + } + } + else + builder.append(" and employee.tenantid NOTNULL"); + + if(criteria.getCreatedDateFrom() != null){ + builder.append(" and employee.createddate >= ?"); + preparedStmtList.add(criteria.getCreatedDateFrom()); + } + + if(criteria.getCreatedDateFrom()!= null){ + builder.append(" and employee.createddate <= ?"); + preparedStmtList.add(criteria.getCreatedDateFrom()); + } + + addOrderByClause(builder, HRMS_QUERY_ORDER_BY_CLAUSE); + + if(criteria.getLimit() != null) { + builder.append(" limit ?"); + preparedStmtList.add(criteria.getLimit()); + } + else { + builder.append(" limit ?"); + preparedStmtList.add(defaultLimit); + } + + if(criteria.getOffset() != null) { + builder.append(" offset ?"); + preparedStmtList.add(criteria.getOffset()); + } + else { + builder.append(" offset ?"); + preparedStmtList.add(0); + } + + return builder.toString(); + } + + public String getPlainSearchEmployeeQuery(EmployeePlainSearchCriteria criteria, List preparedStmtList ) { + StringBuilder builder = new StringBuilder(EmployeeQueries.HRMS_GET_EMPLOYEES); + if(!CollectionUtils.isEmpty(criteria.getUuids())){ + builder.append(" employee.uuid IN (").append(createQuery(criteria.getUuids())+")"); + addToPreparedStatement(preparedStmtList,criteria.getUuids()); + } + else + builder.delete(builder.length() - 6, builder.length()); + + return builder.toString(); + + } + + private static void addOrderByClause(StringBuilder queryBuilder,String columnName) { + queryBuilder.append(" ORDER BY " + columnName); + } } diff --git a/business-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeRepository.java b/business-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeRepository.java index 518fb1dcf..6062a0733 100644 --- a/business-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeRepository.java +++ b/business-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeRepository.java @@ -8,9 +8,11 @@ import org.egov.common.contract.request.RequestInfo; import org.egov.hrms.utils.HRMSUtils; +import org.egov.hrms.web.contract.EmployeePlainSearchCriteria; import org.egov.hrms.web.contract.EmployeeSearchCriteria; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.SingleColumnRowMapper; import org.springframework.stereotype.Repository; import lombok.extern.slf4j.Slf4j; @@ -121,4 +123,31 @@ public Map fetchEmployeeCount(String tenantId){ return response; } + public List fetchPlainSearchEmployees(EmployeePlainSearchCriteria criteria){ + List employees = new ArrayList<>(); + List preparedStmtList = new ArrayList<>(); + + String query = queryBuilder.getPlainSearchEmployeeQuery(criteria, preparedStmtList); + try { + employees = jdbcTemplate.query(query, preparedStmtList.toArray(),rowMapper); + }catch(Exception e) { + log.error("Exception while making the db call -> ",e); + log.error("query -> "+query); + } + return employees; + } + + public List fetchEmployeeIds(EmployeePlainSearchCriteria criteria){ + List employeeIds = new ArrayList<>(); + List preparedStmtList = new ArrayList<>(); + String employeeIdsQuery = queryBuilder.getEmployeeIdsQuery(criteria, preparedStmtList); + try { + employeeIds = jdbcTemplate.query(employeeIdsQuery, new SingleColumnRowMapper<>(String.class), preparedStmtList.toArray()); + }catch(Exception e) { + log.error("Exception while making the db call -> ", e); + log.error("query -> " + employeeIdsQuery); + } + return employeeIds; + } + } diff --git a/business-services/egov-hrms/src/main/java/org/egov/hrms/service/EmployeeService.java b/business-services/egov-hrms/src/main/java/org/egov/hrms/service/EmployeeService.java index f75cf0cb9..b8d5bbb0d 100644 --- a/business-services/egov-hrms/src/main/java/org/egov/hrms/service/EmployeeService.java +++ b/business-services/egov-hrms/src/main/java/org/egov/hrms/service/EmployeeService.java @@ -125,6 +125,7 @@ public EmployeeResponse create(EmployeeRequest employeeRequest) { employee.getUser().setPassword(null); }); hrmsProducer.push(propertiesManager.getSaveEmployeeTopic(), employeeRequest); + hrmsProducer.push(propertiesManager.getSaveEmployeeIndexTopic(), employeeRequest); notificationService.sendNotification(employeeRequest, pwdMap); return generateResponse(employeeRequest); } @@ -214,14 +215,57 @@ public EmployeeResponse search(EmployeeSearchCriteria criteria, RequestInfo requ return EmployeeResponse.builder().responseInfo(factory.createResponseInfoFromRequestInfo(requestInfo, true)) .employees(employees).build(); } - - + /** - * Creates user by making call to egov-user. - * - * @param employee - * @param requestInfo + * Plain search for employees + * + * @param criteria + * @return */ + public List plainsearch(EmployeePlainSearchCriteria criteria,RequestInfo requestInfo) { + if (criteria.getLimit() != null && criteria.getLimit() > propertiesManager.getHrmsMaxLimit()) + criteria.setLimit(propertiesManager.getHrmsMaxLimit()); + + List employeeIds = null; + + if(CollectionUtils.isEmpty(criteria.getUuids())) + employeeIds = repository.fetchEmployeeIds(criteria); + else + employeeIds = criteria.getUuids(); + + EmployeePlainSearchCriteria employeePlainSearchCriteria = EmployeePlainSearchCriteria.builder().uuids(employeeIds).build(); + List employees=repository.fetchPlainSearchEmployees(employeePlainSearchCriteria); + + Map mapOfUsers = new HashMap(); + + if(!CollectionUtils.isEmpty(employeeIds)){ + Map UserSearchCriteria = new HashMap<>(); + UserSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_UUID,employeeIds); + if(mapOfUsers.isEmpty()){ + UserResponse userResponse = userService.getUser(requestInfo, UserSearchCriteria); + if(!CollectionUtils.isEmpty(userResponse.getUser())) { + mapOfUsers = userResponse.getUser().stream() + .collect(Collectors.toMap(User :: getUuid, Function.identity())); + } + } + for(Employee employee: employees){ + employee.setUser(mapOfUsers.get(employee.getUuid())); + } + } + + if(employeeIds.isEmpty()) + return Collections.emptyList(); + + + return employees; + } + + /** + * Creates user by making call to egov-user. + * + * @param employee + * @param requestInfo + */ private void createUser(Employee employee, RequestInfo requestInfo) { enrichUser(employee); UserRequest request = UserRequest.builder().requestInfo(requestInfo).user(employee.getUser()).build(); @@ -344,6 +388,7 @@ public EmployeeResponse update(EmployeeRequest employeeRequest) { updateUser(employee, requestInfo); }); hrmsProducer.push(propertiesManager.getUpdateTopic(), employeeRequest); + hrmsProducer.push(propertiesManager.getUpdateEmployeeIndexTopic(), employeeRequest); //notificationService.sendReactivationNotification(employeeRequest); return generateResponse(employeeRequest); } diff --git a/business-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeePlainSearchCriteria.java b/business-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeePlainSearchCriteria.java new file mode 100644 index 000000000..228ba5e8d --- /dev/null +++ b/business-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeePlainSearchCriteria.java @@ -0,0 +1,40 @@ +package org.egov.hrms.web.contract; + +import lombok.*; +import org.apache.commons.lang3.StringUtils; +import javax.validation.constraints.Size; +import java.util.List; + + +@AllArgsConstructor +@Getter +@NoArgsConstructor +@Setter +@ToString +@Builder +public class EmployeePlainSearchCriteria { + + @Size(max = 250) + public String tenantId; + + private List uuids; + + private Long createdDateFrom; + + private Long createdDateTo; + + public Integer offset; + + public Integer limit; + + + public boolean isPlainSearchCriteriaEmpty(EmployeePlainSearchCriteria criteria) { + if(StringUtils.isEmpty(criteria.getTenantId()) && null == createdDateFrom + && null == createdDateTo) { + return true; + }else { + return false; + } + } + +} diff --git a/business-services/egov-hrms/src/main/java/org/egov/hrms/web/controller/EmployeeController.java b/business-services/egov-hrms/src/main/java/org/egov/hrms/web/controller/EmployeeController.java index 1bf065440..8676b3878 100644 --- a/business-services/egov-hrms/src/main/java/org/egov/hrms/web/controller/EmployeeController.java +++ b/business-services/egov-hrms/src/main/java/org/egov/hrms/web/controller/EmployeeController.java @@ -43,6 +43,7 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.contract.request.RequestInfo; import org.egov.hrms.service.EmployeeService; +import org.egov.hrms.utils.ResponseInfoFactory; import org.egov.hrms.web.contract.*; import org.egov.hrms.web.validator.EmployeeValidator; import org.springframework.beans.factory.annotation.Autowired; @@ -67,6 +68,8 @@ public class EmployeeController { @Autowired private EmployeeValidator validator; + @Autowired + private ResponseInfoFactory factory; /** * Maps Post Requests for _create & returns ResponseEntity of either @@ -146,5 +149,13 @@ private ResponseEntity countV1(@RequestParam("tenantId") String tenantId, @Re return new ResponseEntity<>(response,HttpStatus.OK); } + @PostMapping("/_plainsearch") + @ResponseBody + private ResponseEntity plainsearch(@RequestBody @Valid RequestInfoWrapper requestInfoWrapper, @ModelAttribute @Valid EmployeePlainSearchCriteria criteria,@RequestBody RequestInfo requestInfo) { + + EmployeeResponse employeeResponse = EmployeeResponse.builder().responseInfo(factory.createResponseInfoFromRequestInfo(requestInfoWrapper.getRequestInfo(), true)) + .employees(employeeService.plainsearch(criteria,requestInfo)).build(); + return new ResponseEntity<>(employeeResponse,HttpStatus.OK); + } } \ No newline at end of file diff --git a/business-services/egov-hrms/src/main/resources/application.properties b/business-services/egov-hrms/src/main/resources/application.properties index bbeb4a68a..71a102711 100644 --- a/business-services/egov-hrms/src/main/resources/application.properties +++ b/business-services/egov-hrms/src/main/resources/application.properties @@ -17,7 +17,7 @@ spring.flyway.enabled=true #--------------------------- PATH & PORT CONFIGURATIONS ---------------------------# server.contextPath=/egov-hrms server.servlet.context-path=/egov-hrms -server.port=9999 +server.port=8091 #---------------------------- TIMEZONE CONFIGURATIONS -----------------------------# app.timezone=UTC @@ -68,6 +68,7 @@ egov.hrms.employee.app.link=https://mseva.lgpunjab.gov.in/employee/user/login #CONFIGS egov.hrms.default.pagination.limit=200 +egov.hrms.max.pagination.limit=1000 egov.hrms.default.pwd.length=8 open.search.enabled.roles=SUPERUSER egov.pwd.allowed.special.characters=@#$% @@ -91,6 +92,8 @@ kafka.topics.save.service=save-hrms-employee kafka.topics.update.service=update-hrms-employee kafka.topics.notification.sms=egov.core.notification.sms kafka.topics.hrms.updateData= egov-hrms-update +kafka.topics.save.service.index=save-hrms-employee-index +kafka.topics.update.service.index=update-hrms-employee-index spring.kafka.listener.missing-topics-fatal=false diff --git a/frontend/mgramseva/lib/model/demand/demand_list.dart b/frontend/mgramseva/lib/model/demand/demand_list.dart index 723ae2757..93f894ffe 100644 --- a/frontend/mgramseva/lib/model/demand/demand_list.dart +++ b/frontend/mgramseva/lib/model/demand/demand_list.dart @@ -153,6 +153,10 @@ class AggragateDemandDetails { double? netDueWithPenalty; @JsonKey(name: "totalApplicablePenalty") double? totalApplicablePenalty; + @JsonKey(name: "latestDemandCreatedTime") + double? latestDemandCreatedTime; + @JsonKey(name: "latestDemandPenaltyCreatedtime") + double? latestDemandPenaltyCreatedtime; @JsonKey(name: "mapOfDemandDetailList") List>>? mapOfDemandDetailList; AggragateDemandDetails(); diff --git a/frontend/mgramseva/lib/model/demand/demand_list.g.dart b/frontend/mgramseva/lib/model/demand/demand_list.g.dart index 46eec48b0..fa1596193 100644 --- a/frontend/mgramseva/lib/model/demand/demand_list.g.dart +++ b/frontend/mgramseva/lib/model/demand/demand_list.g.dart @@ -149,6 +149,10 @@ AggragateDemandDetails _$AggragateDemandDetailsFromJson( ..netDueWithPenalty = (json['netDueWithPenalty'] as num?)?.toDouble() ..totalApplicablePenalty = (json['totalApplicablePenalty'] as num?)?.toDouble() + ..latestDemandCreatedTime = + (json['latestDemandCreatedTime'] as num?)?.toDouble() + ..latestDemandPenaltyCreatedtime = + (json['latestDemandPenaltyCreatedtime'] as num?)?.toDouble() ..mapOfDemandDetailList = (json['mapOfDemandDetailList'] as List?) ?.map((e) => (e as Map).map( @@ -175,6 +179,8 @@ Map _$AggragateDemandDetailsToJson( 'netdue': instance.netdue, 'netDueWithPenalty': instance.netDueWithPenalty, 'totalApplicablePenalty': instance.totalApplicablePenalty, + 'latestDemandCreatedTime': instance.latestDemandCreatedTime, + 'latestDemandPenaltyCreatedtime': instance.latestDemandPenaltyCreatedtime, 'mapOfDemandDetailList': instance.mapOfDemandDetailList, }; diff --git a/frontend/mgramseva/lib/providers/consumer_details_provider.dart b/frontend/mgramseva/lib/providers/consumer_details_provider.dart index 27667409d..33296b33c 100644 --- a/frontend/mgramseva/lib/providers/consumer_details_provider.dart +++ b/frontend/mgramseva/lib/providers/consumer_details_provider.dart @@ -313,7 +313,7 @@ class ConsumerProvider with ChangeNotifier { "aadharNumber": waterconnection.addharCtrl.text.trim().isEmpty ? null : waterconnection.addharCtrl.text.trim(), - "remarks": property.owners?.first.remarks + "remarks": waterconnection.status == "Inactive" ? property.owners?.first.remarks : "" }); } else { waterconnection.additionalDetails!.locality = @@ -338,8 +338,8 @@ class ConsumerProvider with ChangeNotifier { waterconnection.previousReading; waterconnection.additionalDetails!.propertyType = property.propertyType; - waterconnection.additionalDetails!.remarks = - property.owners?.first.remarks; + waterconnection.additionalDetails!.remarks = waterconnection.status == "Inactive" ? + property.owners?.first.remarks : ""; } try { diff --git a/frontend/mgramseva/lib/screeens/add_expense/expense_details.dart b/frontend/mgramseva/lib/screeens/add_expense/expense_details.dart index ae4a8085d..bf3edb21e 100644 --- a/frontend/mgramseva/lib/screeens/add_expense/expense_details.dart +++ b/frontend/mgramseva/lib/screeens/add_expense/expense_details.dart @@ -163,32 +163,34 @@ class _ExpenseDetailsState extends State { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ - HomeBack( - widget: Help( - callBack: () => showGeneralDialog( - barrierLabel: "Label", - barrierDismissible: false, - barrierColor: Colors.black.withOpacity(0.5), - transitionDuration: Duration(milliseconds: 700), - context: context, - pageBuilder: (context, anim1, anim2) { - return ExpenseWalkThroughContainer((index) => - expenseProvider.incrementindex( - index, - expenseProvider - .expenseWalkthrougList[index + 1].key)); - }, - transitionBuilder: (context, anim1, anim2, child) { - return SlideTransition( - position: - Tween(begin: Offset(0, 1), end: Offset(0, 0)) - .animate(anim1), - child: child, - ); - }, - ), - walkThroughKey: Constants.ADD_EXPENSE_KEY, - )), + // ExpenseWalkThroughContainer Is Removed + // HomeBack( + // widget: Help( + // callBack: () => showGeneralDialog( + // barrierLabel: "Label", + // barrierDismissible: false, + // barrierColor: Colors.black.withOpacity(0.5), + // transitionDuration: Duration(milliseconds: 700), + // context: context, + // pageBuilder: (context, anim1, anim2) { + // return ExpenseWalkThroughContainer((index) => + // expenseProvider.incrementindex( + // index, + // expenseProvider + // .expenseWalkthrougList[index + 1].key)); + // }, + // transitionBuilder: (context, anim1, anim2, child) { + // return SlideTransition( + // position: + // Tween(begin: Offset(0, 1), end: Offset(0, 0)) + // .animate(anim1), + // child: child, + // ); + // }, + // ), + // walkThroughKey: Constants.ADD_EXPENSE_KEY, + // )), + HomeBack(), Card( child: Consumer( builder: (_, expensesDetailsProvider, child) => Form( @@ -462,18 +464,23 @@ class _ExpenseDetailsState extends State { expenseProvider.expenseWalkthrougList[4].key, key: Keys.expense.EXPENSE_PARTY_DATE, ), - RadioButtonFieldBuilder( - context, - i18.expense.HAS_THIS_BILL_PAID, - expensesDetailsProvider - .expenditureDetails.isBillPaid, - '', - '', - true, - Constants.EXPENSESTYPE, - expensesDetailsProvider.onChangeOfBillPaid, - isEnabled: expensesDetailsProvider - .expenditureDetails.allowEdit), + AbsorbPointer( + absorbing: expensesDetailsProvider + .expenditureDetails + .isBillCancelled == true ? true : false, + child: RadioButtonFieldBuilder( + context, + i18.expense.HAS_THIS_BILL_PAID, + expensesDetailsProvider + .expenditureDetails.isBillPaid, + '', + '', + true, + Constants.EXPENSESTYPE, + expensesDetailsProvider.onChangeOfBillPaid, + isEnabled: expensesDetailsProvider + .expenditureDetails.allowEdit), + ), if (expensesDetailsProvider.expenditureDetails.isBillPaid ?? false) BasicDateField(i18.expense.PAYMENT_DATE, true, expensesDetailsProvider.expenditureDetails.paidDateCtrl, @@ -579,7 +586,7 @@ class _ExpenseDetailsState extends State { onChanged: expensesDetailsProvider .expenditureDetails .allowEdit == - true + true && expensesDetailsProvider.expenditureDetails.isBillPaid == false ? expensesDetailsProvider .onChangeOfCheckBox : null), @@ -593,8 +600,8 @@ class _ExpenseDetailsState extends State { fontSize: 19, color: expensesDetailsProvider .expenditureDetails - .allowEdit == - true + .allowEdit == + true && expensesDetailsProvider.expenditureDetails.isBillPaid == false ? Colors.black : Colors.grey, fontWeight: diff --git a/frontend/mgramseva/lib/screeens/consumer_details/consumer_details.dart b/frontend/mgramseva/lib/screeens/consumer_details/consumer_details.dart index 4db67c9d2..d39e940f3 100644 --- a/frontend/mgramseva/lib/screeens/consumer_details/consumer_details.dart +++ b/frontend/mgramseva/lib/screeens/consumer_details/consumer_details.dart @@ -157,32 +157,34 @@ class _ConsumerDetailsState extends State { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ - HomeBack( - widget: Help( - callBack: () => showGeneralDialog( - barrierLabel: "Label", - barrierDismissible: false, - barrierColor: Colors.black.withOpacity(0.5), - transitionDuration: Duration(milliseconds: 700), - context: context, - pageBuilder: (context, anim1, anim2) { - return WalkThroughContainer((index) => - consumerProvider.incrementIndex( - index, - consumerProvider - .consmerWalkthrougList[index + 1].key)); - }, - transitionBuilder: (context, anim1, anim2, child) { - return SlideTransition( - position: - Tween(begin: Offset(0, 1), end: Offset(0, 0)) - .animate(anim1), - child: child, - ); - }, - ), - walkThroughKey: Constants.CREATE_CONSUMER_KEY, - )), + // ConsmerWalkthrougList Is Removed + // HomeBack( + // widget: Help( + // callBack: () => showGeneralDialog( + // barrierLabel: "Label", + // barrierDismissible: false, + // barrierColor: Colors.black.withOpacity(0.5), + // transitionDuration: Duration(milliseconds: 700), + // context: context, + // pageBuilder: (context, anim1, anim2) { + // return WalkThroughContainer((index) => + // consumerProvider.incrementIndex( + // index, + // consumerProvider + // .consmerWalkthrougList[index + 1].key)); + // }, + // transitionBuilder: (context, anim1, anim2, child) { + // return SlideTransition( + // position: + // Tween(begin: Offset(0, 1), end: Offset(0, 0)) + // .animate(anim1), + // child: child, + // ); + // }, + // ), + // walkThroughKey: Constants.CREATE_CONSUMER_KEY, + // )), + HomeBack(), Card( child: Column( mainAxisAlignment: MainAxisAlignment.start, @@ -654,13 +656,15 @@ class _ConsumerDetailsState extends State { (consumerProvider.waterconnection.status == "Inactive"), child: Consumer( - builder: (_, consumerProvider, child) { - property.owners!.first.consumerRemarksCtrl - .text = consumerProvider.waterconnection - .additionalDetails!.remarks ?? - ""; + builder: (_, consumerProvider, child) { + + property.owners!.first.consumerRemarksCtrl + .text = consumerProvider.waterconnection + .additionalDetails!.remarks ?? + ""; + + return BuildTextField( - i18.consumer.CONSUMER_REMARKS, property.owners!.first.consumerRemarksCtrl, validator: (val) => diff --git a/frontend/mgramseva/lib/screeens/generate_bill/widgets/count_table_widget.dart b/frontend/mgramseva/lib/screeens/generate_bill/widgets/count_table_widget.dart index 51587cbfd..06d99ffb1 100644 --- a/frontend/mgramseva/lib/screeens/generate_bill/widgets/count_table_widget.dart +++ b/frontend/mgramseva/lib/screeens/generate_bill/widgets/count_table_widget.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:flutter/material.dart'; import 'package:mgramseva/model/reports/WaterConnectionCount.dart'; import 'package:mgramseva/utils/constants/i18_key_constants.dart'; @@ -27,18 +29,10 @@ class _CountTableWidgetState extends State { children: [ LayoutBuilder( builder: (context, constraints) { - if (constraints.maxWidth <= 760) { return Container( width: MediaQuery.of(context).size.width, - child: FittedBox( - child: _buildDataTable(connectionCount!), - ), + child: _buildDataTable(connectionCount!), ); - } else { - return Container( - width: MediaQuery.of(context).size.width, - child: _buildDataTable(connectionCount!)); - } }, ), if (connectionCount!.length > 5) @@ -96,6 +90,7 @@ class _CountTableWidgetState extends State { return DataRow( color: MaterialStateColor.resolveWith((states) => rowColor!), // Apply alternate row background color + cells: [ DataCell( Text( diff --git a/frontend/mgramseva/lib/screeens/home/home.dart b/frontend/mgramseva/lib/screeens/home/home.dart index 456266158..232df70df 100644 --- a/frontend/mgramseva/lib/screeens/home/home.dart +++ b/frontend/mgramseva/lib/screeens/home/home.dart @@ -44,30 +44,31 @@ class _HomeState extends State { _buildView(homeProvider, Widget notification) { return Column(children: [ - Align( - alignment: Alignment.centerRight, - child: Help( - callBack: () => showGeneralDialog( - barrierLabel: "Label", - barrierDismissible: false, - barrierColor: Colors.black.withOpacity(0.5), - transitionDuration: Duration(milliseconds: 700), - context: context, - pageBuilder: (context, anim1, anim2) { - return HomeWalkThroughContainer((index) => - homeProvider.incrementIndex(index, - homeProvider.homeWalkthroughList[index + 1].key)); - }, - transitionBuilder: (context, anim1, anim2, child) { - return SlideTransition( - position: Tween(begin: Offset(0, 1), end: Offset(0, 0)) - .animate(anim1), - child: child, - ); - }, - ), - walkThroughKey: Constants.HOME_KEY, - )), + /* Note : WalkThroughContainer Is Removed */ + // Align( + // alignment: Alignment.centerRight, + // child: Help( + // callBack: () => showGeneralDialog( + // barrierLabel: "Label", + // barrierDismissible: false, + // barrierColor: Colors.black.withOpacity(0.5), + // transitionDuration: Duration(milliseconds: 700), + // context: context, + // pageBuilder: (context, anim1, anim2) { + // return HomeWalkThroughContainer((index) => + // homeProvider.incrementIndex(index, + // homeProvider.homeWalkthroughList[index + 1].key)); + // }, + // transitionBuilder: (context, anim1, anim2, child) { + // return SlideTransition( + // position: Tween(begin: Offset(0, 1), end: Offset(0, 0)) + // .animate(anim1), + // child: child, + // ); + // }, + // ), + // walkThroughKey: Constants.HOME_KEY, + // )), HomeCard(), notification, Footer() diff --git a/frontend/micro-ui/web/micro-ui-internals/example/.env-mgram-uat b/frontend/micro-ui/web/micro-ui-internals/example/.env-mgram-uat new file mode 100644 index 000000000..691df07e8 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/.env-mgram-uat @@ -0,0 +1,7 @@ +SKIP_PREFLIGHT_CHECK=true +REACT_APP_USER_TYPE=EMPLOYEE +REACT_APP_EMPLOYEE_TOKEN=c835932f-2ad4-4d05-83d6-49e0b8c59f8a +REACT_APP_CITIZEN_TOKEN=7cd58aae-30b3-41ed-a1b3-3417107a993c +REACT_APP_PROXY_API=https://mgramseva-uat.psegs.in +REACT_APP_PROXY_ASSETS=https://mgramseva-uat.psegs.in +REACT_APP_GLOBAL=https://egov-dev-assets.s3.ap-south-1.amazonaws.com/globalConfigsMgramsewa.js \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/example/devpackage.json b/frontend/micro-ui/web/micro-ui-internals/example/devpackage.json index 625090509..5a963764d 100644 --- a/frontend/micro-ui/web/micro-ui-internals/example/devpackage.json +++ b/frontend/micro-ui/web/micro-ui-internals/example/devpackage.json @@ -12,6 +12,7 @@ "@egovernments/digit-ui-libraries":"^1.4.0", "@egovernments/digit-ui-module-common":"^1.4.0", "@egovernments/digit-ui-module-engagement":"^1.4.0", + "@egovernments/digit-ui-module-payment":"0.0.14", "@egovernments/digit-ui-module-fsm":"^1.4.0", "@egovernments/digit-ui-module-mcollect":"^1.4.0", "@egovernments/digit-ui-module-noc":"^1.4.0", diff --git a/frontend/micro-ui/web/micro-ui-internals/example/package.json b/frontend/micro-ui/web/micro-ui-internals/example/package.json index ea63ba6af..978def326 100644 --- a/frontend/micro-ui/web/micro-ui-internals/example/package.json +++ b/frontend/micro-ui/web/micro-ui-internals/example/package.json @@ -14,6 +14,7 @@ "@egovernments/digit-ui-module-core": "1.5.46", "@egovernments/digit-ui-module-hrms": "1.5.27", "@egovernments/digit-ui-module-pgr": "1.7.0", + "@egovernments/digit-ui-module-payment":"0.0.14", "@egovernments/digit-ui-module-engagement": "1.5.20", "@egovernments/digit-ui-react-components": "1.5.26", "http-proxy-middleware": "^1.0.5", diff --git a/frontend/micro-ui/web/micro-ui-internals/example/public/index.html b/frontend/micro-ui/web/micro-ui-internals/example/public/index.html index 37582faef..76b10cb74 100644 --- a/frontend/micro-ui/web/micro-ui-internals/example/public/index.html +++ b/frontend/micro-ui/web/micro-ui-internals/example/public/index.html @@ -10,7 +10,11 @@ mGramSeva - + + + + + diff --git a/frontend/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js b/frontend/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js index 6d17ab0d5..4addde2b4 100644 --- a/frontend/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js +++ b/frontend/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js @@ -7,6 +7,15 @@ import _ from "lodash"; var Digit = window.Digit || {}; +function anonymizeHalfString(input) { + // Calculate the midpoint of the string + const midpoint = Math.ceil(input.length / 2); + + // Replace the first 50% of the string with asterisks + const anonymized = "*".repeat(midpoint) + input.substring(midpoint); + + return anonymized; +} const businessServiceMap = { @@ -425,4 +434,170 @@ export const UICustomizations = { } } }, + OpenPaymentSearch:{ + preProcess: (data, additionalDetails) => { + + //we need to get three things -> consumerCode,businessService,tenantId + // businessService and tenantId can be either in queryParams or in form + let {consumerCode,businessService,tenantId} = data?.state?.searchForm || {}; + businessService = businessService?.code + tenantId = tenantId?.[0]?.code + if(!businessService){ + businessService = additionalDetails?.queryParams?.businessService + } + if(!tenantId){ + tenantId = additionalDetails?.queryParams?.tenantId + } + const finalParams = { + // consumerCode, + tenantId, + businessService, + connectionNumber:consumerCode, + isOpenPaymentSearch:true + } + data.params = finalParams + // data.params.textSearch = finalParams.consumerCode + // const tenantId = Digit.ULBService.getCurrentTenantId(); + // data.body = { RequestInfo: data.body.RequestInfo }; + // const { limit, offset } = data?.state?.tableForm || {}; + // const { campaignName, campaignType } = data?.state?.searchForm || {}; + // data.body.CampaignDetails = { + // tenantId: tenantId, + // status: ["failed"], + // createdBy: Digit.UserService.getUser().info.uuid, + // pagination: { + // sortBy: "createdTime", + // sortOrder: "desc", + // limit: limit, + // offset: offset, + // }, + // }; + // if (campaignName) { + // data.body.CampaignDetails.campaignName = campaignName; + // } + // if (campaignType) { + // data.body.CampaignDetails.projectType = campaignType?.[0]?.code; + // } + delete data.body.custom; + delete data.body.pagination; + data.options = { + userService:false, + auth:false + } + // delete data.body.inbox; + // delete data.params; + return data; + }, + additionalCustomizations: (row, key, column, value, t, searchResult) => { + + switch (key) { + case "OP_CONS_CODE": + return + + {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} + + + + case "OP_APPLICATION_TYPE": + return
+ { value ? t(Digit.Utils.locale.getTransformedLocale(`OP_APPLICATION_TYPE_${value}`)) : t("ES_COMMON_NA")} +
+ + case "OP_APPLICATION_STATUS": + return
+ { value ? t(Digit.Utils.locale.getTransformedLocale(`OP_APPLICATION_STATUS_${value}`)) : t("ES_COMMON_NA")} +
+ case "OP_CONNECTION_TYPE": + return
+ { value ? t(Digit.Utils.locale.getTransformedLocale(`OP_CONNECTION_TYPE_${value}`)) : t("ES_COMMON_NA")} +
+ case "OP_METER_INSTALLATION_DATE": + return
+ {value ? Digit.DateUtils.ConvertEpochToDate(value) : t("ES_COMMON_NA")} +
+ case "OP_METER_READING_DATE": + return
+ {value ? Digit.DateUtils.ConvertEpochToDate(value) : t("ES_COMMON_NA")} +
+ case "OP_PROPERTY_TYPE": + return
+ { value ? t(Digit.Utils.locale.getTransformedLocale(`OP_PROPERTY_TYPE_${value}`)) : t("ES_COMMON_NA")} +
+ case "OP_PAYER_NAME": + return
+ {value ? anonymizeHalfString(value) : t("ES_COMMON_NA")} +
+ + + default: + return {t("ES_COMMON_DEFAULT_NA")} + } + if (key === "OP_BILL_DATE") { + return Digit.DateUtils.ConvertEpochToDate(value); + } + + if(key === "OP_BILL_TOTAL_AMT"){ + return {`₹ ${value}`} + } + + if(key === "OP_CONS_CODE") { + return + + {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} + + + } + }, + populateReqCriteria: () => { + const tenantId = Digit.ULBService.getCurrentTenantId(); + return { + url: "/mdms-v2/v1/_search", + params: { tenantId }, + body: { + MdmsCriteria: { + tenantId, + moduleDetails: [ + { + moduleName: "tenant", + masterDetails: [ + { + name: "tenants", + }, + ], + }, + ], + }, + }, + config: { + enabled: true, + select: (data) => { + const result = data?.MdmsRes?.tenant?.tenants?.filter(row => row?.divisionCode && row?.divisionName)?.map(row => { + return { + ...row, + updatedCode:`${row.divisionName} - ${row?.name}` + } + }); + return result; + }, + }, + }; + }, + customValidationCheck: (data) => { + + //checking both to and from date are present + const { consumerCode } = data; + if(!consumerCode) return false; + if(consumerCode.length < 10 || consumerCode.length > 25){ + return { warning: true, label: "ES_COMMON_ENTER_VALID_CONSUMER_CODE" }; + } + // if ((createdFrom === "" && createdTo !== "") || (createdFrom !== "" && createdTo === "")) + // return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" }; + + return false; + } + } }; diff --git a/frontend/micro-ui/web/micro-ui-internals/example/src/index.js b/frontend/micro-ui/web/micro-ui-internals/example/src/index.js index 0a103644a..6a520e8a0 100644 --- a/frontend/micro-ui/web/micro-ui-internals/example/src/index.js +++ b/frontend/micro-ui/web/micro-ui-internals/example/src/index.js @@ -7,6 +7,7 @@ import { initDSSComponents } from "@egovernments/digit-ui-module-dss"; import { initEngagementComponents } from "@egovernments/digit-ui-module-engagement"; import { initHRMSComponents } from "@egovernments/digit-ui-module-hrms"; import { initPGRComponents, PGRReducers } from "@egovernments/digit-ui-module-pgr"; +import {initPaymentComponents} from "@egovernments/digit-ui-module-payment"; import "@egovernments/digit-ui-css/example/index.css"; import { pgrCustomizations } from "./pgr"; @@ -18,6 +19,7 @@ const enabledModules = [ "DSS", "HRMS", "PGR", + "Payment" // "Engagement", "NDSS","QuickPayLinks", "Payment", // "Utilities", //added to check fsm @@ -63,6 +65,7 @@ const initDigitUI = () => { initHRMSComponents(); initEngagementComponents(); initPGRComponents(); + initPaymentComponents(); const moduleReducers = (initData) => ({ pgr: PGRReducers(initData), diff --git a/frontend/micro-ui/web/micro-ui-internals/package.json b/frontend/micro-ui/web/micro-ui-internals/package.json index dfbfd4ff1..2f6b4f69d 100644 --- a/frontend/micro-ui/web/micro-ui-internals/package.json +++ b/frontend/micro-ui/web/micro-ui-internals/package.json @@ -26,6 +26,7 @@ "dev:components": "cd packages/react-components && yarn start", "dev:pgr": "cd packages/modules/pgr && yarn start", "dev:hrms": "cd packages/modules/hrms && yarn start", + "dev:payment": "cd packages/modules/payment && yarn start", "dev:core": "cd packages/modules/core && yarn start", "dev:example": "cd example && yarn start", "build": "run-p build:**", @@ -35,6 +36,7 @@ "build:pgr": "cd packages/modules/pgr && yarn build", "build:hrms": "cd packages/modules/hrms && yarn build", "build:core": "cd packages/modules/core && yarn build", + "build:payment": "cd packages/modules/payment && yarn build", "build:sample": "cd packages/modules/sample && yarn build", "deploy:jenkins": "./scripts/jenkins.sh", "clean": "rm -rf node_modules" diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/package.json b/frontend/micro-ui/web/micro-ui-internals/packages/css/package.json index fa4b0ee9e..1e4e5f0d8 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/package.json +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/package.json @@ -1,6 +1,6 @@ { "name": "@egovernments/digit-ui-css", - "version": "1.5.50", + "version": "1.5.54", "license": "MIT", "main": "dist/index.css", "author": "Jagankumar ", diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/components/textfields.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/components/textfields.scss index 715140131..233153613 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/components/textfields.scss +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/components/textfields.scss @@ -9,6 +9,14 @@ .employee-card-input { @apply mb-lg pl-sm outline-none block border w-full h-10 border-input-border border-solid bg-white leading-10 text-form-field text-text-primary; } + +.employee-card-input-only { +} +.employee-card-input-only .employee-card-input { + @apply mb-lg pl-sm outline-none block border w-full h-12 border-input-border border-solid bg-white leading-10 text-form-field text-text-primary; +} + + .employee-card-input:disabled { @apply border-grey-dark text-grey-dark !important; pointer-events: none !important; @@ -82,6 +90,10 @@ } } +.citizen-card-input-only { + @apply mb-lg pl-sm outline-none block border w-full h-12 border-input-border border-solid bg-white leading-10 text-form-field text-text-primary; +} + .citizen-card-input { @apply mb-lg pl-sm outline-none block border w-full h-10 border-input-border border-solid bg-white leading-10 text-form-field text-text-primary; } diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/inbox.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/inbox.scss index b19e0b2d1..839c86b07 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/inbox.scss +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/inbox.scss @@ -447,6 +447,16 @@ height: 263px !important; } } + +@screen dt { + .customEmployeeWarnings { + margin-left: 2.6rem !important; + margin-top: -4rem !important; + width: 65% !important; + } +} + + .employeeTotalLink { color: theme(colors.text.secondary); font-size: 16px; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/hooks/payment.js b/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/hooks/payment.js index 255ac45ff..abbddd89c 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/hooks/payment.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/hooks/payment.js @@ -95,12 +95,12 @@ export const useFetchPayment = ({ tenantId, consumerCode, businessService }, con }; }; -export const usePaymentUpdate = ({ egId }, businessService, config) => { +export const usePaymentUpdate = ({ egId }, businessService, config,auth=true,userService=true) => { const getPaymentData = async (egId) => { - const transaction = await Digit.PaymentService.updateCitizenReciept(egId); + const transaction = await Digit.PaymentService.updateCitizenReciept(egId,auth,userService); const payments = await Digit.PaymentService.getReciept(transaction.Transaction[0].tenantId, businessService, { consumerCodes: transaction.Transaction[0].consumerCode, - }); + },auth,userService); return { payments, applicationNo: transaction.Transaction[0].consumerCode, txnStatus: transaction.Transaction[0].txnStatus }; }; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/hooks/useCustomAPIHook.js b/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/hooks/useCustomAPIHook.js index a9a6273e4..40faadcf0 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/hooks/useCustomAPIHook.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/hooks/useCustomAPIHook.js @@ -30,12 +30,12 @@ import { CustomService } from "../services/elements/CustomService"; */ -const useCustomAPIHook = ({ url, params, body, config = {}, plainAccessRequest,changeQueryName="Random" }) => { +const useCustomAPIHook = ({ url, params, body, config = {}, plainAccessRequest,changeQueryName="Random",options={} }) => { const client = useQueryClient(); const { isLoading, data, isFetching } = useQuery( [url,changeQueryName].filter((e) => e), - () => CustomService.getResponse({ url, params, body, plainAccessRequest }), + () => CustomService.getResponse({ url, params, body, plainAccessRequest,...options }), { cacheTime:0, ...config, diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/services/atoms/Utils/Request.js b/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/services/atoms/Utils/Request.js index f8e6bd630..cbace88a2 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/services/atoms/Utils/Request.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/services/atoms/Utils/Request.js @@ -56,7 +56,7 @@ export const Request = async ({ headers = {}, useCache = false, params = {}, - auth, + auth=true, urlParams = {}, userService, locale = true, @@ -74,7 +74,7 @@ export const Request = async ({ data.RequestInfo = { apiId: "Rainmaker", }; - if (auth || !!Digit.UserService.getUser()?.access_token) { + if (auth) { data.RequestInfo = { ...data.RequestInfo, ...requestInfo() }; } if (userService) { diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/services/elements/CustomService.js b/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/services/elements/CustomService.js index 58c7ae673..053ca9e97 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/services/elements/CustomService.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/services/elements/CustomService.js @@ -1,14 +1,14 @@ import { Request } from "../atoms/Utils/Request"; export const CustomService = { - getResponse: ({ url, params, body, plainAccessRequest,useCache=true,userService=true,setTimeParam=true ,userDownload=false}) => + getResponse: ({ url, params, body, plainAccessRequest,useCache=true,userService=true,setTimeParam=true,userDownload=false,auth=true}) => Request({ url: url, data: body, useCache, userService, method: "POST", - auth: true, + auth: auth, params: params, plainAccessRequest: plainAccessRequest, userDownload:userDownload, diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/services/elements/Payment.js b/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/services/elements/Payment.js index d54d5a62a..4b160c90d 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/services/elements/Payment.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/services/elements/Payment.js @@ -49,7 +49,7 @@ export const PaymentService = { data: { ...details }, }), - getReciept: (tenantId, businessservice, filters = {}) => + getReciept: (tenantId, businessservice, filters = {},auth=true,userService=true) => Request({ url: businessservice && businessservice !== "BPAREG" @@ -57,8 +57,8 @@ export const PaymentService = { : `${Urls.payment.print_reciept}/_search`, useCache: false, method: "POST", - auth: true, - userService: true, + auth, + userService, params: { tenantId, ...filters }, }), @@ -95,13 +95,13 @@ export const PaymentService = { data: { ...details }, }), - updateCitizenReciept: (transactionId) => + updateCitizenReciept: (transactionId,auth=true,userService=true) => Request({ url: Urls.payment.update_citizen_reciept, useCache: false, method: "POST", - auth: true, - userService: true, + auth, + userService, params: { transactionId }, }), diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/core/src/components/ChangeCity.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/core/src/components/ChangeCity.js index a21e8d69c..c41abeb61 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/core/src/components/ChangeCity.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/core/src/components/ChangeCity.js @@ -22,7 +22,6 @@ const ChangeCity = (prop) => { const history = useHistory(); const isDropdown = prop.dropdown || false; let selectedCities = []; - const uuids = [prop.userDetails?.info?.uuid]; const { data: userData, isUserDataLoading } = Digit.Hooks.useUserSearch(Digit.ULBService.getStateId(), { uuid: uuids }, {}); // setSelectedCity(userData?.data?.user[0]?.roles) @@ -39,6 +38,7 @@ const ChangeCity = (prop) => { loggedInData.info.roles = filteredRoles; loggedInData.info.tenantId = city?.value; } + Digit.SessionStorage.set("Employee.tenantId", city?.value); Digit.UserService.setUser(loggedInData); setDropDownData(city); @@ -54,8 +54,8 @@ const ChangeCity = (prop) => { let teantsArray = [],filteredArray = []; userData?.user[0].roles?.forEach((role) => teantsArray.push(role.tenantId)); let unique = teantsArray.filter((item, i, ar) => ar.indexOf(item) === i); - unique?.forEach((uniCode) => { + data?.MdmsRes?.["tenant"]["tenants"]?.map((items) => { if (items?.code !== "pb" && items?.code === uniCode) { filteredArray.push({ @@ -74,6 +74,7 @@ const ChangeCity = (prop) => { }); selectedCities = filteredArray?.filter((select) => select.value == Digit.SessionStorage.get("Employee.tenantId")); setSelectCityData(filteredArray); + }, [dropDownData, data?.MdmsRes]); return ( diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/core/src/components/TopBarSideBar/TopBar.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/core/src/components/TopBarSideBar/TopBar.js index efaa32f86..af1405bd3 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/core/src/components/TopBarSideBar/TopBar.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/core/src/components/TopBarSideBar/TopBar.js @@ -74,8 +74,8 @@ const TopBar = ({ const urlsToDisableNotificationIcon = (pathname) => !!Digit.UserService?.getUser()?.access_token ? false - : [`/${window?.contextPath}/citizen/select-language`, `/${window?.contextPath}/citizen/select-location`].includes(pathname); - + : [`/${window?.contextPath}/citizen/select-language`, `/${window?.contextPath}/citizen/select-location`,`/mgramseva-web/citizen/payment`].includes(pathname); + if (CITIZEN) { return (
diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/core/src/pages/citizen/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/core/src/pages/citizen/index.js index ac66a2ceb..a3c54a261 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/core/src/pages/citizen/index.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/core/src/pages/citizen/index.js @@ -23,6 +23,7 @@ const sidebarHiddenFor = [ `/${window?.contextPath}/citizen/select-location`, `/${window?.contextPath}/citizen/login`, `/${window?.contextPath}/citizen/register/otp`, + `/citizen/payment/`, ]; const getTenants = (codes, tenants) => { diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/core/src/pages/employee/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/core/src/pages/employee/index.js index edd21baf6..1846ecb62 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/core/src/pages/employee/index.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/core/src/pages/employee/index.js @@ -1,4 +1,4 @@ -import React, { useEffect } from "react"; +import React, { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { Redirect, Route, Switch, useLocation, useRouteMatch, useHistory } from "react-router-dom"; import { AppModules } from "../../components/AppModules"; @@ -10,7 +10,10 @@ import LanguageSelection from "./LanguageSelection"; import EmployeeLogin from "./Login"; import UserProfile from "../citizen/Home/UserProfile"; import ErrorComponent from "../../components/ErrorComponent"; -import { PrivateRoute } from "@egovernments/digit-ui-react-components"; +import { PrivateRoute, Card, CardText, CardSubHeader, CardLabelError } from "@egovernments/digit-ui-react-components"; + + + const userScreensExempted = ["user/profile", "user/error"]; @@ -36,10 +39,51 @@ const EmployeeApp = ({ const location = useLocation(); const showLanguageChange = location?.pathname?.includes("language-selection"); const isUserProfile = userScreensExempted.some((url) => location?.pathname?.includes(url)); + const DIV_ADMIN = Digit.UserService.hasAccess(["DIV_ADMIN"]); + const MDMS_ADMIN = Digit.UserService.hasAccess(["MDMS_ADMIN"]); + const STATE_ADMIN = Digit.UserService.hasAccess(["STATE_ADMIN"]); + + + const [showAlert, setShowAlert] = useState(false); useEffect(() => { Digit.UserService.setType("employee"); + + + + if(userDetails?.info?.roles.some(obj => obj.name === "STATE ADMIN")){ + setShowAlert(false); + } + if (cityDetails.code == "pb") { + if( DIV_ADMIN == 0 && MDMS_ADMIN ==1 && STATE_ADMIN == 1){ + setShowAlert(false); + } + if(DIV_ADMIN == 0 && MDMS_ADMIN ==0 && STATE_ADMIN == 0){ + setShowAlert(true); + + }else{ + setShowAlert(false); + + } + } + else{ + setShowAlert(false); + } + + + // if (cityDetails.code == "pb") { + // setShowAlert(true); + // } + // else { + // setShowAlert(false); + // } }, []); + const closeAlert = () => { + setShowAlert(false); + }; + + + return (
@@ -113,7 +157,25 @@ const EmployeeApp = ({ + {/* ALERT BOX */} + { (userDetails?.info?.roles.some(obj => obj.name === "STATE ADMIN") ? false : true ) && showAlert &&
{/* Centered row */} + +
+
+
+ {t("CS_COMMON_SELECT_TITLE_VILLAGE")} + {t("CS_COMMON_SELECT_VILLAGE")} + {/* */} +
+
+
+
+
} + {/* ALERT BOX */} + +
+
Powered by DIGIT +
{moduleName} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/MultiSelectDropdown.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/MultiSelectDropdown.js new file mode 100644 index 000000000..87a3fcee4 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/MultiSelectDropdown.js @@ -0,0 +1,141 @@ +import React, { useEffect, useReducer, useRef, useState } from "react"; +import { ArrowDown, CheckSvg } from "@egovernments/digit-ui-react-components"; +import { useTranslation } from "react-i18next"; + +const MultiSelectDropdown = ({ options, optionsKey, selected = [], onSelect, defaultLabel = "", defaultUnit = "",BlockNumber=1,isOBPSMultiple=false,props={},isPropsNeeded=false,ServerStyle={}, isSurvey=false,placeholder, disable=false,config}) => { + const [active, setActive] = useState(false); + const [searchQuery, setSearchQuery] = useState(); + const [optionIndex, setOptionIndex] = useState(-1); + const dropdownRef = useRef(); + const { t } = useTranslation(); + + function reducer(state, action){ + switch(action.type){ + case "ADD_TO_SELECTED_EVENT_QUEUE": + return [...state, {[optionsKey]: action.payload?.[1]?.[optionsKey], propsData: action.payload} ] + case "REMOVE_FROM_SELECTED_EVENT_QUEUE": + const newState = state.filter( e => e?.[optionsKey] !== action.payload?.[1]?.[optionsKey]) + onSelect(newState.map((e) => e.propsData), props); + return newState + case "REPLACE_COMPLETE_STATE": + return action.payload + default: + return state + } + } + + useEffect(() => { + dispatch({type: "REPLACE_COMPLETE_STATE", payload: fnToSelectOptionThroughProvidedSelection(selected) }) + },[selected?.length, selected?.[0]?.code]) + + function fnToSelectOptionThroughProvidedSelection(selected){ + return selected?.map( e => ({[optionsKey]: e?.[optionsKey], propsData: [null, e]})) + } + + const [alreadyQueuedSelectedState, dispatch] = useReducer(reducer, selected, fnToSelectOptionThroughProvidedSelection) + + useEffect(()=> { + if(!active){ + onSelect(alreadyQueuedSelectedState?.map( e => e.propsData), props) + } + },[active]) + + + function handleOutsideClickAndSubmitSimultaneously(){ + setActive(false) + } + + Digit.Hooks.useClickOutside(dropdownRef, handleOutsideClickAndSubmitSimultaneously , active, {capture: true} ); + const filtOptns = + searchQuery?.length > 0 ? options.filter((option) => t(option[optionsKey]&&typeof option[optionsKey]=="string" && option[optionsKey].toUpperCase()).toLowerCase().indexOf(searchQuery.toLowerCase()) >= 0) : options; + + function onSearch(e) { + setSearchQuery(e.target.value); + } + + function onSelectToAddToQueue(...props){ + const isChecked = arguments[0].target.checked + isChecked ? dispatch({type: "ADD_TO_SELECTED_EVENT_QUEUE", payload: arguments }) : dispatch({type: "REMOVE_FROM_SELECTED_EVENT_QUEUE", payload: arguments }) + } + +/* Custom function to scroll and select in the dropdowns while using key up and down */ + const keyChange = (e) => { + if (e.key == "ArrowDown") { + setOptionIndex(state =>state+1== filtOptns.length?0:state+1); + if(optionIndex+1== filtOptns.length){ + e?.target?.parentElement?.parentElement?.children?.namedItem("jk-dropdown-unique")?.scrollTo?.(0,0) + }else{ + optionIndex>2&& e?.target?.parentElement?.parentElement?.children?.namedItem("jk-dropdown-unique")?.scrollBy?.(0,45) + } + e.preventDefault(); + } else if (e.key == "ArrowUp") { + setOptionIndex(state => state!==0? state - 1: filtOptns.length-1); + if(optionIndex===0){ + e?.target?.parentElement?.parentElement?.children?.namedItem("jk-dropdown-unique")?.scrollTo?.(100000,100000) + }else{ + optionIndex>2&&e?.target?.parentElement?.parentElement?.children?.namedItem("jk-dropdown-unique")?.scrollBy?.(0,-45) + } + e.preventDefault(); + }else if(e.key=="Enter"){ + onSelectToAddToQueue(e,filtOptns[optionIndex]); + } + } + + const MenuItem = ({ option, index }) => ( +
+ selectedOption[optionsKey] === option[optionsKey]) ? true : false} + onChange={(e) => isPropsNeeded?onSelectToAddToQueue(e, option,props):isOBPSMultiple?onSelectToAddToQueue(e, option,BlockNumber):onSelectToAddToQueue(e, option)} + style={{minWidth: "24px", width: "100%"}} + disabled={option.isDisabled || false} + /> +
+ +
+

{t(option[optionsKey]&&typeof option[optionsKey]=="string" && option[optionsKey])}

+
+ ); + + const Menu = () => { + const filteredOptions = + searchQuery?.length > 0 ? options.filter((option) => t(option[optionsKey]&&typeof option[optionsKey]=="string" && option[optionsKey].toUpperCase()).toLowerCase().indexOf(searchQuery.toLowerCase()) >= 0) : options; + return filteredOptions?.map((option, index) => ); + }; + + return ( +
+
+
+ setActive(true)} value={searchQuery} onChange={onSearch} placeholder={t(placeholder)} /> +
+

{alreadyQueuedSelectedState.length > 0 ? `${isSurvey? alreadyQueuedSelectedState?.filter((ob) => ob?.i18nKey !== undefined).length : alreadyQueuedSelectedState.length} ${defaultUnit}` : defaultLabel}

+ +
+
+ {active ? ( +
+ +
+ ) : null} + +
+ {config?.isDropdownWithChip ?
+ {alreadyQueuedSelectedState.length > 0 && + alreadyQueuedSelectedState.map((value, index) => { + return onSelectToAddToQueue(e, value,props) + : (e) => onSelectToAddToQueue(e, value) + } />; + })} +
: null} +
+ ); +}; + +export default MultiSelectDropdown; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/SearchUserForm.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/SearchUserForm.js new file mode 100644 index 000000000..9e1a3a999 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/SearchUserForm.js @@ -0,0 +1,443 @@ +import { Loader, Header, Dropdown, LabelFieldPair, CardLabel, LinkLabel, SubmitBar, Toast } from "@egovernments/digit-ui-react-components"; +import React, { useState, useMemo, useEffect } from "react"; +import { useTranslation } from "react-i18next"; +import { Controller, useForm, useWatch } from "react-hook-form"; +import MultiSelectDropdown from "./MultiSelectDropdown"; +function filterKeys(data, keys) { + return data.map((item) => { + const filteredItem = {}; + keys.forEach((key) => { + if (item.hasOwnProperty(key)) { + filteredItem[key] = item[key]; + } + }); + return filteredItem; + }); +} + +function getUniqueLeafCodes(tree) { + const codes = new Set(); + + function traverse(node) { + if (!node || typeof node !== "object") return; + + const keys = Object.keys(node).filter((key) => key !== "options" && key !== "codes"); + + // Check if it's a leaf node (all remaining keys' values are strings) + const isLeafNode = keys.every((key) => typeof node[key] === "string"); + + if (isLeafNode && node.code) { + codes.add(node.code); + } else { + // Traverse every other key except options and codes + keys.forEach((key) => { + if (typeof node[key] === "object") { + traverse(node[key]); + } + }); + } + } + + traverse(tree); + + return Array.from(codes); +} + +function buildTree(data, hierarchy) { + const tree = { options: [] }; + + data.forEach((item) => { + // Ignore items without zoneCode + if (!item.zoneCode) return; + + let currentLevel = tree; + + hierarchy.forEach(({ level }, index) => { + const value = item[level]; + + if (!currentLevel[value]) { + // Clone the item and delete the options property from it + const clonedItem = { ...item }; + delete clonedItem.options; + + // Initialize the current level with the cloned item + currentLevel[value] = { ...clonedItem, options: [] }; + + // Push the cloned item to the options array without the options property + currentLevel.options.push({ ...clonedItem }); + } + + if (index === hierarchy.length - 1) { + currentLevel[value].codes = currentLevel[value].codes || []; + currentLevel[value].codes.push(item.code); + } + + currentLevel = currentLevel[value]; + }); + }); + + return tree; +} + +const SearchUserForm = ({ uniqueTenants, setUniqueTenants, roles, setUniqueRoles }) => { + const { t } = useTranslation(); + const [showToast, setShowToast] = useState(null); + const [hierarchy, setHierarchy] = useState([ + { level: "zoneCode", value: 1, optionsKey: "zoneName", isMandatory: true }, + { level: "circleCode", value: 2, optionsKey: "circleName", isMandatory: true }, + { level: "divisionCode", value: 3, optionsKey: "divisionName", isMandatory: true }, + { level: "subDivisionCode", value: 4, optionsKey: "subDivisionName", isMandatory: false }, + { level: "sectionCode", value: 5, optionsKey: "sectionName", isMandatory: false }, + // { "level": "schemeCode", "value": 6,"optionsKey":"schemeName" }, + { level: "code", value: 7, optionsKey: "name", isMandatory: false }, + ]); + const [tree, setTree] = useState(null); + const [rolesOptions,setRolesOptions] = useState(null) + // const [zones,setZones] = useState([]) + // const [circles,setCircles] = useState([]) + // const [divisions,setDivisions] = useState([]) + // const [subDivisions,setSubDivisions] = useState([]) + // const [sections,setSections] = useState([]) + // const [schemes,setSchemes] = useState([]) + // const [codes,setCodes] = useState([]) + + const requestCriteria = { + url: "/mdms-v2/v1/_search", + params: { tenantId: Digit.ULBService.getStateId() }, + body: { + MdmsCriteria: { + tenantId: Digit.ULBService.getStateId(), + moduleDetails: [ + { + moduleName: "tenant", + masterDetails: [ + { + name: "tenants", + }, + ], + }, + { + moduleName: "ws-services-masters", + masterDetails: [ + { + name: "WSServiceRoles", + }, + ], + } + ], + }, + }, + config: { + cacheTime: Infinity, + select: (data) => { + const requiredKeys = [ + "code", + "name", + "zoneCode", + "zoneName", + "circleCode", + "circleName", + "divisionCode", + "divisionName", + "subDivisionCode", + "subDivisionName", + "sectionCode", + "sectionName", + "schemeCode", + "schemeName", + ]; + const result = data?.MdmsRes?.tenant?.tenants; + const filteredResult = filterKeys(result, requiredKeys); + const resultInTree = buildTree(filteredResult, hierarchy); + const excludeCodes = ["HRMS_ADMIN", "LOC_ADMIN", "MDMS_ADMIN", "EMPLOYEE", "SYSTEM"]; + setRolesOptions(data?.MdmsRes?.["ws-services-masters"]?.["WSServiceRoles"]?.filter(row => !excludeCodes.includes(row?.code))) + //updating to state roles as requested + // setRolesOptions([ + // // { + // // code: "", + // // name: "Select All", + // // description: "", + // // }, + // { + // code: "EMPLOYEE", + // name: "EMPLOYEE", + // labelKey: "ACCESSCONTROL_ROLES_ROLES_EMPLOYEE", + // }, + // { + // code: "DIV_ADMIN", + // name: "DIVISION ADMIN", + // labelKey: "ACCESSCONTROL_ROLES_ROLES_DIV_ADMIN", + // }, + // { + // code: "HRMS_ADMIN", + // name: "HRMS_ADMIN", + // labelKey: "ACCESSCONTROL_ROLES_ROLES_HRMS_ADMIN", + // }, + // { + // code: "MDMS_ADMIN", + // name: "MDMS Admin", + // description: "Mdms admin", + // }, + + // ]) + setTree(resultInTree); + return result; + }, + }, + }; + + const { isLoading, data, revalidate, isFetching, error } = Digit.Hooks.useCustomAPIHook(requestCriteria); + + const { + register, + handleSubmit, + setValue, + getValues, + reset, + watch, + trigger, + control, + formState, + errors, + setError, + clearErrors, + unregister, + } = useForm({ + defaultValues: { + "zoneCode": "", + "circleCode": "", + "divisionCode": "", + "subDivisionCode": "", + "sectionCode": "", + "code": "", + "roles": [] + }, + }); + + const formData = watch(); + + const clearSearch = () => { + reset({ + "zoneCode": "", + "circleCode": "", + "divisionCode": "", + "subDivisionCode": "", + "sectionCode": "", + "code": "", + "roles": [] + }); + setUniqueRoles(null); + setUniqueTenants(null); + + // dispatch({ + // type: uiConfig?.type === "filter"?"clearFilterForm" :"clearSearchForm", + // state: { ...uiConfig?.defaultValues } + // //need to pass form with empty strings + // }) + //here reset tableForm as well + // dispatch({ + // type: "tableForm", + // state: { limit:10,offset:0 } + // //need to pass form with empty strings + // }) + }; + + const onSubmit = (data) => { + //assuming atleast one hierarchy is entered + + if (Object.keys(data).length === 0 || Object.values(data).every((value) => !value)) { + //toast message + setShowToast({ warning: true, label: t("ES_COMMON_MIN_SEARCH_CRITERIA_MSG") }); + setTimeout(closeToast, 5000); + return; + } + //other validations if any + //check mandatory fields + let areMandatoryFieldsNotFilled = false; + hierarchy.forEach(({ level, isMandatory }) => { + if (isMandatory && (!data[level] || data[level]?.length === 0)) { + areMandatoryFieldsNotFilled = true; + return; // Exit the loop early + } + }); + + if (areMandatoryFieldsNotFilled) { + setShowToast({ warning: true, label: t("ES_COMMON_MIN_SEARCH_CRITERIA_MSG") }); + setTimeout(closeToast, 5000); + return; + } + + //checking roles + if(data?.roles?.length === 0 || !data?.roles){ + setShowToast({ warning: true, label: t("ES_COMMON_MIN_SEARCH_CRITERIA_MSG") }); + setTimeout(closeToast, 5000); + return; + } + + //here apply a logic to compute the subtree based on the hierarchy selected + const levels = hierarchy.map(({ level }) => level); + //compute current level + let maxSelectedLevel = levels[0]; + levels.forEach((level) => { + if (formData[level]) { + maxSelectedLevel = level; + } else { + return; + } + }); + + const levelIndex = levels.indexOf(maxSelectedLevel); + + let currentLevel = tree; + for (let i = 0; i <= levelIndex; i++) { + const code = data?.[levels[i]]?.[levels[i]]; + if (!code || !currentLevel[code]) return []; + currentLevel = currentLevel[code]; + } + + //this is the list of tenants under the current subtree + const listOfUniqueTenants = getUniqueLeafCodes(currentLevel); + setUniqueTenants(() => listOfUniqueTenants); + setUniqueRoles(() => data?.roles?.filter(row=>row.code)?.map(role=> role.code)); + }; + + const optionsForHierarchy = (level, value) => { + if (!tree) return []; + + const levels = hierarchy.map(({ level }) => level); + const levelIndex = levels.indexOf(level); + + //zoneCode(1st level(highest parent)) + if (levelIndex === -1 || levelIndex === 0) return tree.options; + + let currentLevel = tree; + for (let i = 0; i < levelIndex; i++) { + const code = formData[levels[i]]?.[levels[i]]; + if (!code || !currentLevel[code]) return []; + currentLevel = currentLevel[code]; + } + return currentLevel.options || []; + }; + + const closeToast = () => { + setShowToast(null); + }; + + const renderHierarchyFields = useMemo(() => { + return hierarchy.map(({ level, optionsKey, isMandatory, ...rest }, idx) => ( + + {`${t(Digit.Utils.locale.getTransformedLocale(`HR_SU_${level}`))} ${ + isMandatory ? "*" : "" + }`} + ( + { + props.onChange(e); + //clear all child levels + const childLevels = hierarchy.slice(hierarchy.findIndex((h) => h.level === level) + 1); + childLevels.forEach((child) => setValue(child.level, "")); + }} + selected={props.value} + defaultValue={props.value} + t={t} + optionCardStyles={{ + top: "2.3rem", + overflow: "auto", + maxHeight: "200px", + }} + /> + )} + rules={{}} + defaultValue={""} + name={level} + control={control} + /> + + )); + }, [formData]); + + if (isLoading || !setTree) { + return ; + } + + return ( +
+
+
+

{t("HR_SU_HINT")}

+
+ {renderHierarchyFields} + + {`${t(Digit.Utils.locale.getTransformedLocale(`HR_SU_ROLES`))} ${"*"}`} + { + return ( +
+ { + props.onChange( + e + ?.map((row) => { + return row?.[1] ? row[1] : null; + }) + .filter((e) => e) + ) + }} + selected={props?.value || []} + defaultLabel={t("HR_SU_SELECT_ROLES")} + defaultUnit={ t("COMMON_ROLES_SELECTED")} + // showSelectAll={true} + t={t} + // config={config} + // disable={false} + // optionsDisable={config?.optionsDisable} + /> +
+ ) + }} + rules={{}} + defaultValue={[]} + name={"roles"} + control={control} + /> +
+
+ { + clearSearch(); + }} + > + {t("HR_SU_CLEAR_SEARCH")} + + +
+
+
+
+ {showToast && ( + { + closeToast(); + }} + isDleteBtn={true} + /> + )} +
+ ); +}; + +export default SearchUserForm; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/SearchUserResults.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/SearchUserResults.js new file mode 100644 index 000000000..0d9529dd0 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/SearchUserResults.js @@ -0,0 +1,122 @@ +import React from 'react' +import { useTranslation } from "react-i18next"; +import { Table,Loader,Card } from "@egovernments/digit-ui-react-components"; +import { Link } from "react-router-dom"; + +const SearchUserResults = ({isLoading,data,...props}) => { + const { t } = useTranslation(); + const GetCell = (value) => {t(value)}; + const GetSlaCell = (value) => { + return value == "INACTIVE" ? ( + {t(value) || ""} + ) : ( + {t(value) || ""} + ); + }; + + const columns = React.useMemo(() => { + return [ + { + Header: t("HR_EMP_ID_LABEL"), + disableSortBy: false, + accessor: "code", + Cell: ({ row }) => { + return ( + + {row.original.code} + + // GetCell(`${row.original?.code}`) + ); + }, + }, + { + Header: t("HR_EMP_NAME_LABEL"), + disableSortBy: false, + accessor: "name", + Cell: ({ row }) => { + return GetCell(`${row.original?.user?.name}`); + }, + }, + { + Header: t("HR_USER_ID_LABEL"), + disableSortBy: false, + accessor: "mobileNumber", + Cell: ({ row }) => { + return GetCell(`${row.original?.user?.mobileNumber}`); + }, + }, + { + Header: t("HR_STATUS_LABEL"), + disableSortBy: false, + accessor: "isActive", + Cell: ({ row }) => { + return GetSlaCell(`${row.original?.isActive ? "ACTIVE" : "INACTIVE"}`); + }, + }, + { + Header: t("HR_SU_TENANT"), + disableSortBy: false, + accessor: "tenantId", + Cell: ({ row }) => { + return GetCell(`${row.original?.tenantId}`); + }, + }, + ]; + }, [data]); + + let result; + + if (isLoading) { + result = ; + } else if (data?.length === 0) { + result = ( + + {/* TODO Change localization key */} + {t("COMMON_TABLE_NO_RECORD_FOUND") + .split("\\n") + .map((text, index) => ( +

+ {text} +

+ ))} +
+ ); + } else if (data?.length > 0) { + result = ( + { + return { + style: { + maxWidth: cellInfo.column.Header == t("HR_EMP_ID_LABEL") ? "150px" : "", + padding: "20px 18px", + fontSize: "16px", + minWidth: "150px", + }, + }; + }} + // onNextPage={onNextPage} + // onPrevPage={onPrevPage} + // currentPage={currentPage} + totalRecords={data ? data.length : 0} + // onPageSizeChange={onPageSizeChange} + // pageSizeLimit={pageSizeLimit} + // onSort={onSort} + // sortParams={sortParams} + // disableSort={disableSort} + autoSort={true} + manualPagination={false} + /> + ); + } + + return ( +
+ {result} +
+ ) +} + +export default SearchUserResults \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/hrmscard.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/hrmscard.js index bff488035..455ddb85b 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/hrmscard.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/hrmscard.js @@ -24,7 +24,8 @@ const HRMSCard = () => { const { isLoading, isError, error, data, ...rest } = Digit.Hooks.hrms.useHRMSCount(tenantId, roles); const moduleForSomeDIVAdmin = - DIV_ADMIN && MDMS_ADMIN + + DIV_ADMIN && MDMS_ADMIN ? [ { label: t("WORK_BENCH_URL_MASTER_DATA"), @@ -38,10 +39,10 @@ const HRMSCard = () => { : []; const moduleForSomeSTATEUser = - STATE_ADMIN && MDMS_ADMIN + STATE_ADMIN && MDMS_ADMIN ? [ { - label: t("WORK_BENCH_URL_MASTER_DATA"), + label: t("WORK_BENCH_URL_VILLAGE_MASTER_DATA"), link: `${window?.location?.origin}/workbench-ui/employee/workbench/mdms-search-v2?moduleName=tenant&masterName=tenants`, }, ] @@ -74,6 +75,10 @@ const HRMSCard = () => { }, ], links: [ + { + label: t("HR_SEARCH_USER"), + link: `/${window?.contextPath}/employee/hrms/search-user`, + }, { label: t("HR_HOME_SEARCH_RESULTS_HEADING"), link: `/${window?.contextPath}/employee/hrms/inbox`, @@ -82,7 +87,7 @@ const HRMSCard = () => { label: STATE_ADMIN ? t("HR_COMMON_CREATE_DIVISION_EMPLOYEE_HEADER") : t("HR_COMMON_CREATE_EMPLOYEE_HEADER"), link: `/${window?.contextPath}/employee/hrms/create`, }, - { + DIV_ADMIN ? {}: { label: t("HR_STATE_ REPORTS"), link: "https://ifix-dwss.psegs.in/digit-ui/employee/dss/dashboard/ifix", }, diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/inbox/search.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/inbox/search.js index 33e6be599..801c8e6e1 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/inbox/search.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/inbox/search.js @@ -57,6 +57,8 @@ const SearchApplication = ({ onSearch, type, onClose, searchFields, searchParams )}
+ + {searchFields ?.filter((e) => true) ?.map((input, index) => ( @@ -66,12 +68,12 @@ const SearchApplication = ({ onSearch, type, onClose, searchFields, searchParams {input.type !== "date" ? (
{input?.componentInFront ? ( - + {input?.componentInFront} ) : null} - -
+ +
) : ( } @@ -83,8 +85,14 @@ const SearchApplication = ({ onSearch, type, onClose, searchFields, searchParams ))} - -
+ {/* Updated Search & Clear All Button */} +
+
{type === "desktop" && !mobileView && ( {clearAll()} @@ -99,6 +107,24 @@ const SearchApplication = ({ onSearch, type, onClose, searchFields, searchParams /> )}
+
+
+ {/*Don't Remove : Chance of Updated Search & Clear All Button*/} + {/*
+ {type === "desktop" && !mobileView && ( + + {clearAll()} + + )} + {type === "desktop" && !mobileView && ( + + )} +
*/} {(type === "mobile" || mobileView) && ( diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/pageComponents/Multiselect.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/pageComponents/Multiselect.js index 7020d3f4a..752bec612 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/pageComponents/Multiselect.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/pageComponents/Multiselect.js @@ -109,7 +109,9 @@ const MultiSelectDropdown = ({ useEffect(()=>{ if (alreadyQueuedSelectedState?.length === filteredOptions?.length){ + if(alreadyQueuedSelectedState?.length != 0 && filteredOptions?.length != 0){ setIsSelected(true) + } }else{ setIsSelected(false) diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/pageComponents/jurisdiction.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/pageComponents/jurisdiction.js index af3992ab1..0a4290de8 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/pageComponents/jurisdiction.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/pageComponents/jurisdiction.js @@ -169,6 +169,7 @@ const Jurisdictions = ({ t, config, onSelect, userType, formData }) => { config.key, [...jurisdictionData, ...inactiveJurisdictions].filter((value) => Object.keys(value).length !== 0) ); + }, [jurisdictions, data?.MdmsRes]); // useEffect(() => { // setJuristictionsData(formData?.Jurisdictions); @@ -193,37 +194,56 @@ const Jurisdictions = ({ t, config, onSelect, userType, formData }) => { ]); }; const handleRemoveUnit = (unit) => { - if (unit.id) { - let res = { - id: unit?.id, - hierarchy: unit?.hierarchy?.code, - boundaryType: unit?.boundaryType?.label, - boundary: unit?.boundary?.code, - division: unit?.division?.code, - tenantId: unit?.boundary?.code, - auditDetails: unit?.auditDetails, - isdeleted: true, - isActive: false, - }; - res = cleanup(res); - if (unit?.roles) { - res["roles"] = unit?.roles.map((ele) => { - delete ele.description; - return ele; - }); + if(STATE_ADMIN){ + const updatedJurisdictionsData = jurisdictionsData.filter( + (element) => element.key !== unit.key + ); + setJuristictionsData(updatedJurisdictionsData); + setjurisdictions(updatedJurisdictionsData) + if (FormData.errors?.Jurisdictions?.type == unit.key) { + clearErrors("Jurisdictions"); } - setInactiveJurisdictions([...inactiveJurisdictions, res]); + reviseIndexKeys(); + } - setJuristictionsData((pre) => pre.filter((el) => el.key !== unit.key)); - setjurisdictions((prev) => prev.filter((el) => el.key !== unit.key)); - if (FormData.errors?.Jurisdictions?.type == unit.key) { - clearErrors("Jurisdictions"); + else{ + if (unit.id) { + let res = { + id: unit?.id, + hierarchy: unit?.hierarchy?.code, + boundaryType: unit?.boundaryType?.label, + boundary: unit?.boundary?.code, + division: unit?.division?.code, + tenantId: unit?.boundary?.code, + auditDetails: unit?.auditDetails, + isdeleted: true, + isActive: false, + }; + res = cleanup(res); + if (unit?.roles) { + res["roles"] = unit?.roles.map((ele) => { + delete ele.description; + return ele; + }); + } + setInactiveJurisdictions([...inactiveJurisdictions, res]); + } + setJuristictionsData((pre) => pre.filter((el) => el.key !== unit.key)); + setjurisdictions((prev) => prev.filter((el) => el.key !== unit.key)); + if (FormData.errors?.Jurisdictions?.type == unit.key) { + clearErrors("Jurisdictions"); + } + + reviseIndexKeys(); + } - reviseIndexKeys(); + }; let boundaryTypeoption = []; const [focusIndex, setFocusIndex] = useState(-1); + + function getroledata() { if (STATE_ADMIN) { // Specify the role codes you want to filter diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/EditEmployee/EditForm.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/EditEmployee/EditForm.js index 68a576d10..ec159e99c 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/EditEmployee/EditForm.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/EditEmployee/EditForm.js @@ -112,6 +112,25 @@ const EditForm = ({ tenantId, data }) => { return validEmail && name.match(Digit.Utils.getPattern("Name")); }; + + function hasUniqueTenantIds(items) { + // Create a Set to efficiently store unique tenantIds + const uniqueTenantIds = new Set(); + // Iterate through each item + for (const item of items) { + const tenantId = item.tenantId; + // Check if tenantId already exists in the Set + if (uniqueTenantIds.has(tenantId)) { + // Duplicate found, return false + return false; + } + // Add unique tenantId to the Set + uniqueTenantIds.add(tenantId); + } + // No duplicates found, all tenantIds are unique + return true; + } + const onFormValueChange = (setValue = true, formData) => { if (formData?.SelectEmployeePhoneNumber?.mobileNumber) { setMobileNumber(formData?.SelectEmployeePhoneNumber?.mobileNumber); @@ -132,15 +151,19 @@ const EditForm = ({ tenantId, data }) => { } } } - + if ( formData?.SelectEmployeeGender?.gender.code && formData?.SelectEmployeeName?.employeeName && formData?.SelectEmployeePhoneNumber?.mobileNumber && + STATE_ADMIN ? + (formData?.Jurisdictions?.length && !formData?.Jurisdictions.some(juris => juris?.division == undefined || juris?.divisionBoundary?.length === 0 ) ) + :formData?.Jurisdictions?.length && formData?.Jurisdictions.length && !formData?.Jurisdictions.some(juris => juris?.roles?.length === 0 ) + && checkfield && - // setassigncheck && phonecheck && - checkMailNameNum(formData) + checkMailNameNum(formData)&& + hasUniqueTenantIds(formData?.Jurisdictions) ) { setSubmitValve(true); } else { diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/Inbox.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/Inbox.js index daf0af281..15e18f175 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/Inbox.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/Inbox.js @@ -48,11 +48,13 @@ const Inbox = ({ parentRoute, businessService = "HRMS", initialStates = {}, filt }; } - const checkRoles = requestBody.criteria.roles[0] !== "DIV_ADMIN"; + const checkRoles = requestBody.criteria.roles[0] !== "DIV_ADMIN"; const { data: divisionData, ...rests } = Digit.Hooks.hrms.useHRMSEmployeeSearch(requestBody, isupdate, { - enabled: (STATE_ADMIN && searchParams?.hasOwnProperty("isActive")) || searchParams?.hasOwnProperty("tenantIds") ? true : false, + enabled: !STATE_ADMIN ? false : (STATE_ADMIN && searchParams?.hasOwnProperty("isActive")) || searchParams?.hasOwnProperty("tenantIds") ? true : false, }); + + if (searchParams?.hasOwnProperty("roles")) { roles.roles = searchParams?.roles; @@ -122,10 +124,10 @@ const Inbox = ({ parentRoute, businessService = "HRMS", initialStates = {}, filt const getSearchFields = () => { return [ - { - label: t("HR_NAME_LABEL"), - name: "names", - }, + // { + // label: t("HR_NAME_LABEL"), + // name: "names", + // }, { label: t("HR_MOB_NO_LABEL"), name: "phone", diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/SearchUser.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/SearchUser.js new file mode 100644 index 000000000..ead17dcfd --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/SearchUser.js @@ -0,0 +1,49 @@ +import React,{useState,useEffect} from 'react' +import SearchUserForm from '../components/SearchUserForm' +import SearchUserResults from '../components/SearchUserResults'; +import { Header } from '@egovernments/digit-ui-react-components' +import { useTranslation } from "react-i18next"; + + +const SearchUser = () => { + const {t} = useTranslation() + const [uniqueTenants,setUniqueTenants] = useState(null) + const [roles,setUniqueRoles] = useState(null) + + const requestCriteriaForEmployeeSearch = { + url: "/egov-hrms/employees/_searchListOfEmployee", + params: {}, + body: { + criteria:{ + tenantIds:uniqueTenants, + roles:roles, + type:"EMPLOYEE" + } + }, + config: { + enabled: !!uniqueTenants && !!roles, + select: (data) => { + return data?.Employees + }, + + }, + changeQueryName:{uniqueTenants,roles} + }; + + const { isLoading, data, revalidate, isFetching, error } = Digit.Hooks.useCustomAPIHook(requestCriteriaForEmployeeSearch); + + + return ( +
+
+
{t("HR_SU")}
+ +
+
+ +
+
+ ) +} + +export default SearchUser \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/createEmployee.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/createEmployee.js index 4fca1bacb..411ae2229 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/createEmployee.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/createEmployee.js @@ -85,6 +85,24 @@ const CreateEmployee = () => { const employeeCreateSession = Digit.Hooks.useSessionStorage("NEW_EMPLOYEE_CREATE", {}); const [sessionFormData, setSessionFormData, clearSessionFormData] = employeeCreateSession; + function hasUniqueTenantIds(items) { + // Create a Set to efficiently store unique tenantIds + const uniqueTenantIds = new Set(); + // Iterate through each item + for (const item of items) { + const tenantId = item.tenantId; + // Check if tenantId already exists in the Set + if (uniqueTenantIds.has(tenantId)) { + // Duplicate found, return false + return false; + } + // Add unique tenantId to the Set + uniqueTenantIds.add(tenantId); + } + // No duplicates found, all tenantIds are unique + return true; + } + const onFormValueChange = (setValue = true, formData) => { if (!_.isEqual(sessionFormData, formData)) { setSessionFormData({ ...sessionFormData, ...formData }); @@ -112,11 +130,16 @@ const CreateEmployee = () => { formData?.SelectEmployeeGender?.gender.code && formData?.SelectEmployeeName?.employeeName && formData?.SelectEmployeePhoneNumber?.mobileNumber && - formData?.Jurisdictions.length && - (formData?.Jurisdictions.filter((juris) => juris?.roles?.length).length > 0 || formData?.Jurisdictions.filter((juris) => juris?.divisionBoundary?.length).length > 0) && + formData?.Jurisdictions?.length && + STATE_ADMIN ? + (formData?.Jurisdictions.length && !formData?.Jurisdictions.some(juris => juris?.division == undefined || juris?.divisionBoundary?.length === 0 ) ) + + :formData?.Jurisdictions?.length && formData?.Jurisdictions.length && !formData?.Jurisdictions.some(juris => juris?.roles?.length === 0 ) + && checkfield && phonecheck && - checkMailNameNum(formData) + checkMailNameNum(formData) && + hasUniqueTenantIds(formData?.Jurisdictions) ) { setSubmitValve(true); } else { diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/index.js index 9bf9aeb07..56279ed7e 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/index.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hrms/src/pages/index.js @@ -1,8 +1,8 @@ import { PrivateRoute } from "@egovernments/digit-ui-react-components"; import React,{ useEffect } from "react"; import { useTranslation } from "react-i18next"; -import { Link, Switch, useLocation } from "react-router-dom"; - +import { Link, Switch, useLocation, useHistory } from "react-router-dom"; +import SearchUser from "./SearchUser"; // const {SixFtApart,Rotate360}=SVG; const EmployeeApp = ({ path, url, userType }) => { const { t } = useTranslation(); @@ -14,6 +14,7 @@ const EmployeeApp = ({ path, url, userType }) => { tenantId: tenantId, }, }; + const history = useHistory(); const HRMSResponse = Digit?.ComponentRegistryService?.getComponent("HRMSResponse"); const HRMSDetails = Digit?.ComponentRegistryService?.getComponent("HRMSDetails"); @@ -41,6 +42,7 @@ const EmployeeApp = ({ path, url, userType }) => { {" "} / {location.pathname === `/${window?.contextPath}/employee/hrms/inbox` ? t("HR_COMMON_HEADER") : t("HR_COMMON_HEADER")}

+
history.goBack()}>

Back

( @@ -51,6 +53,7 @@ const EmployeeApp = ({ path, url, userType }) => { } /> } /> } /> + } /> diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/package.json b/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/package.json new file mode 100644 index 000000000..ad8cf2900 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/package.json @@ -0,0 +1,35 @@ +{ + "name": "@egovernments/digit-ui-module-payment", + "version": "0.0.14", + "description": "Open Payments", + "main": "dist/index.js", + "module": "dist/index.modern.js", + "source": "src/Module.js", + "files": [ + "dist" + ], + "scripts": { + "start": "microbundle-crl watch --no-compress --format modern,cjs", + "build": "microbundle-crl --compress --no-sourcemap --format cjs", + "prepublish": "yarn build" + }, + "peerDependencies": { + "react": "17.0.2", + "react-router-dom": "5.3.0" + }, + "dependencies": { + "@egovernments/digit-ui-react-components": "1.8.2-beta.9", + "@egovernments/digit-ui-components": "0.0.2-beta.1", + "react": "17.0.2", + "react-dom": "17.0.2", + "react-i18next": "11.16.2", + "react-query": "3.6.1", + "react-router-dom": "5.3.0", + "jquery": "3.6.0" + }, + "author": "JaganKumar ", + "license": "MIT", + "keywords": [ + + ] +} \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/Module.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/Module.js new file mode 100644 index 000000000..3b5df7df4 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/Module.js @@ -0,0 +1,91 @@ +import { Loader, TourProvider } from "@egovernments/digit-ui-react-components"; +import React from "react"; +import { useRouteMatch } from "react-router-dom"; +import CitizenApp from "./pages/citizen"; +import { CustomisedHooks } from "./hooks"; +import { UICustomizations } from "./configs/UICustomizations"; +import {ErrorBoundary} from "@egovernments/digit-ui-components" + +const PaymentModule = ({ stateCode, userType, tenants }) => { + + const { path, url } = useRouteMatch(); + const tenantId = Digit.ULBService.getCurrentTenantId(); + const moduleCode = ["openpayment", "common-masters", tenantId]; + const language = Digit.StoreData.getCurrentLanguage(); + const { isLoading, data: store } = Digit.Services.useStore({ + stateCode, + moduleCode, + language, + }); + + if (isLoading) { + return ; + } + return ( + + + + + + ) +}; + +const componentsToRegister = { + PaymentModule +}; + +const overrideHooks = () => { + Object.keys(CustomisedHooks).map((ele) => { + if (ele === "Hooks") { + Object.keys(CustomisedHooks[ele]).map((hook) => { + Object.keys(CustomisedHooks[ele][hook]).map((method) => { + setupHooks(hook, method, CustomisedHooks[ele][hook][method]); + }); + }); + } else if (ele === "Utils") { + Object.keys(CustomisedHooks[ele]).map((hook) => { + Object.keys(CustomisedHooks[ele][hook]).map((method) => { + setupHooks(hook, method, CustomisedHooks[ele][hook][method], false); + }); + }); + } else { + Object.keys(CustomisedHooks[ele]).map((method) => { + setupLibraries(ele, method, CustomisedHooks[ele][method]); + }); + } + }); +}; + +/* To Overide any existing hook we need to use similar method */ +const setupHooks = (HookName, HookFunction, method, isHook = true) => { + window.Digit = window.Digit || {}; + window.Digit[isHook ? "Hooks" : "Utils"] = window.Digit[isHook ? "Hooks" : "Utils"] || {}; + window.Digit[isHook ? "Hooks" : "Utils"][HookName] = window.Digit[isHook ? "Hooks" : "Utils"][HookName] || {}; + window.Digit[isHook ? "Hooks" : "Utils"][HookName][HookFunction] = method; +}; +/* To Overide any existing libraries we need to use similar method */ +const setupLibraries = (Library, service, method) => { + window.Digit = window.Digit || {}; + window.Digit[Library] = window.Digit[Library] || {}; + window.Digit[Library][service] = method; +}; + +/* To Overide any existing config/middlewares we need to use similar method */ +const updateCustomConfigs = () => { + setupLibraries("Customizations", "commonUiConfig", { ...window?.Digit?.Customizations?.commonUiConfig, ...UICustomizations }); + // setupLibraries("Utils", "parsingUtils", { ...window?.Digit?.Utils?.parsingUtils, ...parsingUtils }); +}; + +/** + * The `initPaymentComponents` function initializes OpenPayment components by overriding hooks, updating + * custom configurations, and registering components. + */ +const initPaymentComponents = () => { + overrideHooks(); + updateCustomConfigs(); + Object.entries(componentsToRegister).forEach(([key, value]) => { + Digit.ComponentRegistryService.setComponent(key, value); + }); +}; + +export { initPaymentComponents }; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/components/OpenSearch.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/components/OpenSearch.js new file mode 100644 index 000000000..8988dfdb0 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/components/OpenSearch.js @@ -0,0 +1,81 @@ +import React, { useEffect } from "react"; +import { useTranslation } from "react-i18next"; +import { Header, InboxSearchComposer, Loader } from "@egovernments/digit-ui-react-components"; +import { OpenSearchConfig } from "../configs/OpenSearchConfig"; + +const OpenSearch = () => { + const { t } = useTranslation(); + const queryParams = Digit.Hooks.useQueryParams(); + + //An effect to update configs + // useEffect(() => { + // // if (!queryParams.tenantId) { + // // // Update configs + // // OpenSearchConfig.minParametersForSearchForm += 1; + // // OpenSearchConfig.sections.search.uiConfig.minReqFields += 1; + // // OpenSearchConfig.sections.search.uiConfig.defaultValues = { + // // ...OpenSearchConfig.sections.search.uiConfig.defaultValues, + // // tenantId: "" + // // }; + // // OpenSearchConfig.sections.search.uiConfig.fields = [ + // // ...OpenSearchConfig.sections.search.uiConfig.fields, + // // { + // // label: "SELECT_TENANT", + // // type: "dropdown", + // // isMandatory: false, + // // disable: false, + // // populators: { + // // name: "tenantId", + // // optionsKey: "name", + // // optionsCustomStyle: { top: "2.3rem" }, + // // mdmsConfig: { + // // masterName: "tenants", + // // moduleName: "tenant", + // // localePrefix: "TENANT", + // // }, + // // }, + // // }, + // // ]; + // // } + + // if (!queryParams.businessService) { + // // Update configs + // OpenSearchConfig.minParametersForSearchForm += 1; + // OpenSearchConfig.sections.search.uiConfig.minReqFields += 1; + // OpenSearchConfig.sections.search.uiConfig.defaultValues = { + // ...OpenSearchConfig.sections.search.uiConfig.defaultValues, + // businessService: "" + // }; + // OpenSearchConfig.sections.search.uiConfig.fields = [ + // ...OpenSearchConfig.sections.search.uiConfig.fields, + // { + // label: "SELECT_BS", + // type: "dropdown", + // isMandatory: false, + // disable: false, + // populators: { + // name: "businessService", + // optionsKey: "name", + // optionsCustomStyle: { top: "2.3rem" }, + // mdmsConfig: { + // masterName: "BusinessService", + // moduleName: "BillingService", + // localePrefix: "BUSINESS_SERV", + // }, + // }, + // }, + // ]; + // } + // }, []); + + return ( + +
{t(OpenSearchConfig?.label)}
+
+ +
+
+ ); +}; + +export default OpenSearch; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/components/OpenView.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/components/OpenView.js new file mode 100644 index 000000000..baafe512d --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/components/OpenView.js @@ -0,0 +1,367 @@ +import { Loader, StatusTable, Row, Card, Header, SubmitBar, ActionBar, Toast } from "@egovernments/digit-ui-react-components"; +import React, { Fragment, useState, useEffect } from "react"; +import { useTranslation } from "react-i18next"; +import { makePayment } from "../utils/payGov"; +import $ from "jquery"; + +function anonymizeHalfString(input) { + // Calculate the midpoint of the string + const midpoint = Math.ceil(input.length / 2); + + // Replace the first 50% of the string with asterisks + const anonymized = "*".repeat(midpoint) + input.substring(midpoint); + + return anonymized; +} + +const OpenView = () => { + const { t } = useTranslation(); + const [showToast, setShowToast] = useState(null); + const queryParams = Digit.Hooks.useQueryParams(); + const requestCriteria = { + url: "/billing-service/bill/v2/_fetchbill", + params: queryParams, + body: {}, + options: { + userService: false, + auth: false, + }, + config: { + enabled: !!queryParams.consumerCode && !!queryParams.tenantId && !!queryParams.businessService, + select: (data) => { + return data?.Bill?.[0]; + }, + }, + }; + + const { isLoading, data: bill, revalidate, isFetching, error } = Digit.Hooks.useCustomAPIHook(requestCriteria); + + const requestCriteriaForConnectionSearch = { + url: "/ws-services/wc/_search?", + params: { tenantId:queryParams.tenantId,businessService:queryParams.businessService, connectionNumber: queryParams.consumerCode,isOpenPaymentSearch:true }, + body: {}, + options: { + userService: false, + auth: false, + }, + config: { + enabled: !!queryParams.consumerCode && !!queryParams.tenantId && !!queryParams.businessService, + select: (data) => { + return data?.WaterConnection?.[0]; + }, + }, + }; + const { isLoading: isLoadingConnection, data: connection, isFetching: isFetchingConnection, error: errorConnection } = Digit.Hooks.useCustomAPIHook( + requestCriteriaForConnectionSearch + ); + + const requestCriteriaForPayments = { + url: "/collection-services/payments/WS/_search", + params: {consumerCodes:queryParams.consumerCode,tenantId:queryParams.tenantId,businessService:queryParams.businessService}, + body: {}, + options: { + userService: false, + auth: false, + }, + config: { + enabled: !!queryParams.consumerCode && !!queryParams.tenantId && !!queryParams.businessService, + select: (data) => { + const payments = data?.Payments; + if (payments?.length === 0) { + return null; + } else if (payments?.length > 5) { + return payments.slice(0, 5); + } else { + return payments; + } + }, + }, + }; + + const { isLoading: isLoadingPayments, data: payments, isFetching: isFetchingPayments, error: isErrorPayments } = Digit.Hooks.useCustomAPIHook( + requestCriteriaForPayments + ); + + const arrears = + bill?.billDetails + ?.sort((a, b) => b.fromPeriod - a.fromPeriod) + ?.reduce((total, current, index) => (index === 0 ? total : total + current.amount), 0) || 0; + + const onSubmit = async () => { + const filterData = { + Transaction: { + tenantId: bill?.tenantId, + txnAmount: bill.totalAmount, + module: bill.businessService, + billId: bill.id, + consumerCode: bill.consumerCode, + productInfo: "Common Payment", + gateway: "PAYGOV", + taxAndPayments: [ + { + billId: bill.id, + amountPaid: bill.totalAmount, + }, + ], + user: { + name: bill?.payerName, + mobileNumber: bill?.mobileNumber, + tenantId: bill?.tenantId, + emailId: "sriranjan.srivastava@owc.com", + }, + // success + // callbackUrl: `${window.location.protocol}//${window.location.host}/${window.contextPath}/citizen/openpayment/success?consumerCode=${queryParams.consumerCode}&tenantId=${queryParams.tenantId}&businessService=${queryParams.businessService}`, + callbackUrl: `${window.location.protocol}//${window.location.host}/${window.contextPath}/citizen/payment/success/${queryParams.businessService}/${queryParams.consumerCode}/${queryParams.tenantId}`, + additionalDetails: { + isWhatsapp: false, + }, + }, + }; + + try { + const data = await Digit.PaymentService.createCitizenReciept(bill?.tenantId, filterData); + + const redirectUrl = data?.Transaction?.redirectUrl; + // paygov + try { + const gatewayParam = redirectUrl + ?.split("?") + ?.slice(1) + ?.join("?") + ?.split("&") + ?.reduce((curr, acc) => { + var d = acc.split("="); + curr[d[0]] = d[1]; + return curr; + }, {}); + var newForm = $("
", { + action: gatewayParam.txURL, + method: "POST", + target: "_top", + }); + const orderForNDSLPaymentSite = [ + "checksum", + "messageType", + "merchantId", + "serviceId", + "orderId", + "customerId", + "transactionAmount", + "currencyCode", + "requestDateTime", + "successUrl", + "failUrl", + "additionalField1", + "additionalField2", + "additionalField3", + "additionalField4", + "additionalField5", + ]; + + // override default date for UPYOG Custom pay + gatewayParam["requestDateTime"] = gatewayParam["requestDateTime"]?.split(new Date().getFullYear()).join(`${new Date().getFullYear()} `); + + gatewayParam["successUrl"] = redirectUrl?.split("successUrl=")?.[1]?.split("eg_pg_txnid=")?.[0] + "eg_pg_txnid=" + gatewayParam?.orderId; + gatewayParam["failUrl"] = redirectUrl?.split("failUrl=")?.[1]?.split("eg_pg_txnid=")?.[0] + "eg_pg_txnid=" + gatewayParam?.orderId; + // gatewayParam["successUrl"]= data?.Transaction?.callbackUrl; + // gatewayParam["failUrl"]= data?.Transaction?.callbackUrl; + + // var formdata = new FormData(); + + for (var key of orderForNDSLPaymentSite) { + // formdata.append(key,gatewayParam[key]); + + newForm.append( + $("", { + name: key, + value: gatewayParam[key], + // type: "hidden", + }) + ); + } + $(document.body).append(newForm); + newForm.submit(); + makePayment(gatewayParam.txURL, newForm); + } catch (e) { + console.log("Error in payment redirect ", e); + //window.location = redirectionUrl; + } + + // window.location = redirectUrl; + } catch (error) { + let messageToShow = "CS_PAYMENT_UNKNOWN_ERROR_ON_SERVER"; + if (error.response?.data?.Errors?.[0]) { + const { code, message } = error.response?.data?.Errors?.[0]; + messageToShow = code; + } + setShowToast({ key: true, label: t(messageToShow) }); + } + }; + + if (isLoading || isLoadingPayments || isLoadingConnection) { + return ; + } + + return ( + <> +
+ {t("OP_PAYMENT_DETAILS")} +
+ + + {connection && ( + <> + + + {/* */} + + + + + )} + {bill ? ( + <> + {/* + */} + + {/*
*/} + {bill?.billDetails?.[0]?.billAccountDetails + ?.sort((a, b) => a.order - b.order) + .map((amountDetails, index) => ( + + ))} + + {arrears?.toFixed?.(2) ? ( + + ) : null} + +
+ + + ) : ( +
{t("NO_BILLS_AVAILABLE")}
+ )} +
+
+ {payments && ( +
+ {t("OP_CONSUMER_RECEIPTS")} +
+ )} + {payments && + payments.map((payment) => { + return ( + + + + + + {/* */} + + + ); + })} + + + {/* {displayMenu ? : null} */} + + + {showToast && ( + { + setShowToast(null); + }} + isDleteBtn={true} + /> + )} + + ); +}; + +export default OpenView; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/components/Response.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/components/Response.js new file mode 100644 index 000000000..d63ff9318 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/components/Response.js @@ -0,0 +1,722 @@ +import { Banner, Card, CardText, Loader, Row, StatusTable, SubmitBar, DownloadPrefixIcon } from "@egovernments/digit-ui-react-components"; +import React, { useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { useQueryClient } from "react-query"; +import { Link, useParams } from "react-router-dom"; + +export const SuccessfulPayment = (props)=>{ +// if(localStorage.getItem("BillPaymentEnabled")!=="true"){ +// window.history.forward(); +// return null; +// } + return +} + +export const convertEpochToDate = (dateEpoch) => { + // Returning NA in else case because new Date(null) returns Current date from calender + if (dateEpoch) { + const dateFromApi = new Date(dateEpoch); + let month = dateFromApi.getMonth() + 1; + let day = dateFromApi.getDate(); + let year = dateFromApi.getFullYear(); + month = (month > 9 ? "" : "0") + month; + day = (day > 9 ? "" : "0") + day; + return `${day}/${month}/${year}`; + } else { + return "NA"; + } +}; + const WrapPaymentComponent = (props) => { + + const { t } = useTranslation(); + const queryClient = useQueryClient(); + const { eg_pg_txnid: egId, workflow: workflw, propertyId } = Digit.Hooks.useQueryParams(); + const [printing, setPrinting] = useState(false); + const [allowFetchBill, setallowFetchBill] = useState(false); + const { businessService: business_service, consumerCode, tenantId } = useParams(); + + // const { data: bpaData = {}, isLoading: isBpaSearchLoading, isSuccess: isBpaSuccess, error: bpaerror } = Digit.Hooks.obps.useOBPSSearch( + // "", {}, tenantId, { applicationNo: consumerCode }, {}, {enabled:(window.location.href.includes("bpa") || window.location.href.includes("BPA"))} + // ); + + const { isLoading, data, isError } = Digit.Hooks.usePaymentUpdate({ egId }, business_service, { + retry: false, + staleTime: Infinity, + refetchOnWindowFocus: false, + },false,false); + + // const { label } = Digit.Hooks.useApplicationsForBusinessServiceSearch({ businessService: business_service }, { enabled: false }); + + // const { data: demand } = Digit.Hooks.useDemandSearch( + // { consumerCode, businessService: business_service }, + // { enabled: !isLoading, retry: false, staleTime: Infinity, refetchOnWindowFocus: false } + // ); + + // const { data: billData, isLoading: isBillDataLoading } = Digit.Hooks.useFetchPayment( + // { tenantId, consumerCode, businessService: business_service }, + // { enabled: allowFetchBill, retry: false, staleTime: Infinity, refetchOnWindowFocus: false } + // ); + const newTenantId=business_service.includes("WS.ONE_TIME_FEE" || "SW.ONE_TIME_FEE")?Digit.ULBService.getStateId():tenantId; + const { data: reciept_data, isLoading: recieptDataLoading } = Digit.Hooks.useRecieptSearch( + { + tenantId, + businessService: business_service, + receiptNumbers: data?.payments?.Payments?.[0]?.paymentDetails[0].receiptNumber, + }, + { + retry: false, + staleTime: Infinity, + refetchOnWindowFocus: false, + select: (dat) => { + return dat.Payments[0]; + }, + enabled: allowFetchBill, + } + ); + const { data: generatePdfKey } = Digit.Hooks.useCommonMDMS(newTenantId, "common-masters", "ReceiptKey", { + select: (data) => + data["common-masters"]?.uiCommonPay?.filter(({ code }) => business_service?.includes(code))[0]?.receiptKey || "ws-receipt", + retry: false, + staleTime: Infinity, + refetchOnWindowFocus: false, + }); + + const payments = data?.payments; + + useEffect(() => { + return () => { + localStorage.setItem("BillPaymentEnabled","false") + queryClient.clear(); + }; + }, []); + + useEffect(() => { + if (data && data.txnStatus && data.txnStatus !== "FAILURE") { + setallowFetchBill(true); + } + }, [data]); + + if (isLoading || recieptDataLoading) { + return ; + } + + const applicationNo = data?.applicationNo; + + const isMobile = window.Digit.Utils.browser.isMobile(); + + + if (isError || !payments || !payments.Payments || payments.Payments.length === 0 || data.txnStatus === "FAILURE") { + return ( + + + {t("CS_PAYMENT_FAILURE_MESSAGE")} + {!(business_service?.includes("PT")) ? ( + + + + ) : ( + + + + + {/* {business_service?.includes("PT") &&
+ +
} */} +
+ {t("CORE_COMMON_GO_TO_HOME")} +
+
+ )} +
+ ); + } + + const paymentData = data?.payments?.Payments[0]; + const amount = reciept_data?.paymentDetails?.[0]?.totalAmountPaid; + const transactionDate = paymentData?.transactionDate; + const printCertificate = async () => { + //const tenantId = Digit.ULBService.getCurrentTenantId(); + const state = tenantId; + const applicationDetails = await Digit.TLService.search({ applicationNumber: consumerCode, tenantId }); + const generatePdfKeyForTL = "tlcertificate"; + + if (applicationDetails) { + let response = await Digit.PaymentService.generatePdf(state, { Licenses: applicationDetails?.Licenses }, generatePdfKeyForTL); + const fileStore = await Digit.PaymentService.printReciept(state, { fileStoreIds: response.filestoreIds[0] }); + window.open(fileStore[response.filestoreIds[0]], "_blank"); + } + }; + + const printReciept = async () => { + if (printing) return; + setPrinting(true); + let paymentArray=[]; + const tenantId = paymentData?.tenantId; + const state = Digit.ULBService.getStateId(); + let response = { filestoreIds: [payments.Payments[0]?.fileStoreId] }; + if (!paymentData?.fileStoreId) { + let assessmentYear="",assessmentYearForReceipt=""; + let count=0; + let toDate,fromDate; + if(payments.Payments[0].paymentDetails[0].businessService=="PT"){ + + payments.Payments[0].paymentDetails[0].bill.billDetails.map(element => { + + if(element.amount >0 || element.amountPaid>0) + { count=count+1; + toDate=convertEpochToDate(element.toPeriod).split("/")[2]; + fromDate=convertEpochToDate(element.fromPeriod).split("/")[2]; + assessmentYear=assessmentYear==""?fromDate+"-"+toDate+"(Rs."+element.amountPaid+")":assessmentYear+","+fromDate+"-"+toDate+"(Rs."+element.amountPaid+")"; + assessmentYearForReceipt=fromDate+"-"+toDate; + } + + }); + + if(count==0) + { + let toDate=convertEpochToDate( payments.Payments[0].paymentDetails[0].bill.billDetails[0].toPeriod).split("/")[2]; + let fromDate=convertEpochToDate( payments.Payments[0].paymentDetails[0].bill.billDetails[0].fromPeriod).split("/")[2]; + assessmentYear=assessmentYear==""?fromDate+"-"+toDate:assessmentYear+","+fromDate+"-"+toDate; + assessmentYearForReceipt=fromDate+"-"+toDate; + } + + + + const details = { + "assessmentYears": assessmentYear, + "arrearCode": "" + } + + + payments.Payments[0].paymentDetails[0].additionalDetails=details; + printRecieptNew(payments) + } + else { + let details + + if(payments.Payments[0].paymentDetails[0].businessService=="BPAREG") + { + details = {...payments.Payments[0].additionalDetails, + "stakeholderType":"Application" + } + } + payments.Payments[0].additionalDetails=details; + paymentArray[0]=payments.Payments[0] + // console.log("paymentArray",paymentArray) + response = await Digit.PaymentService.generatePdf(state, { Payments: paymentArray }, generatePdfKey); + } + } + const fileStore = await Digit.PaymentService.printReciept(state, { fileStoreIds: response.filestoreIds[0] }); + if (fileStore && fileStore[response.filestoreIds[0]]) { + window.open(fileStore[response.filestoreIds[0]], "_blank"); + } + setPrinting(false); + }; + + const convertDateToEpoch = (dateString, dayStartOrEnd = "dayend") => { + //example input format : "2018-10-02" + try { + const parts = dateString.match(/(\d{4})-(\d{1,2})-(\d{1,2})/); + const DateObj = new Date(Date.UTC(parts[1], parts[2] - 1, parts[3])); + DateObj.setMinutes(DateObj.getMinutes() + DateObj.getTimezoneOffset()); + if (dayStartOrEnd === "dayend") { + DateObj.setHours(DateObj.getHours() + 24); + DateObj.setSeconds(DateObj.getSeconds() - 1); + } + return DateObj.getTime(); + } catch (e) { + return dateString; + } + }; + + const printPdf = (blob) => { + const fileURL = URL.createObjectURL(blob); + var myWindow = window.open(fileURL); + if (myWindow != undefined) { + myWindow.addEventListener("load", (event) => { + myWindow.focus(); + myWindow.print(); + }); + } + }; + + const downloadPdf = (blob, fileName) => { + if (window.mSewaApp && window.mSewaApp.isMsewaApp() && window.mSewaApp.downloadBase64File) { + var reader = new FileReader(); + reader.readAsDataURL(blob); + reader.onloadend = function () { + var base64data = reader.result; + mSewaApp.downloadBase64File(base64data, fileName); + }; + } else { + const link = document.createElement("a"); + // create a blobURI pointing to our Blob + link.href = URL.createObjectURL(blob); + link.download = fileName; + // some browser needs the anchor to be in the doc + document.body.append(link); + link.click(); + link.remove(); + // in case the Blob uses a lot of memory + setTimeout(() => URL.revokeObjectURL(link.href), 7000); + } + }; + + const getPermitOccupancyOrderSearch = async(order, mode="download") => { + let queryObj = { applicationNo: bpaData?.[0]?.applicationNo }; + let bpaResponse = await Digit.OBPSService.BPASearch(bpaData?.[0]?.tenantId, queryObj); + const edcrResponse = await Digit.OBPSService.scrutinyDetails(bpaData?.[0]?.tenantId, { edcrNumber: bpaData?.[0]?.edcrNumber }); + let bpaDataDetails = bpaResponse?.BPA?.[0], edcrData = edcrResponse?.edcrDetail?.[0]; + let currentDate = new Date(); + bpaDataDetails.additionalDetails.runDate = convertDateToEpoch( + currentDate.getFullYear() + "-" + (currentDate.getMonth() + 1) + "-" + currentDate.getDate() + ); + let reqData = { ...bpaDataDetails, edcrDetail: [{ ...edcrData }] }; + // console.log("reqData",reqData) + let response = await Digit.PaymentService.generatePdf(bpaDataDetails?.tenantId, { Bpa: [reqData] }, order); + const fileStore = await Digit.PaymentService.printReciept(bpaDataDetails?.tenantId, { fileStoreIds: response.filestoreIds[0] }); + window.open(fileStore[response?.filestoreIds[0]], "_blank"); + + reqData["applicationType"] = bpaDataDetails?.additionalDetails?.applicationType; + let edcrresponse = await Digit.OBPSService.edcr_report_download({ BPA: { ...reqData } }); + const responseStatus = parseInt(edcrresponse.status, 10); + if (responseStatus === 201 || responseStatus === 200) { + mode == "print" + ? printPdf(new Blob([edcrresponse.data], { type: "application/pdf" })) + : downloadPdf(new Blob([edcrresponse.data], { type: "application/pdf" }), `edcrReport.pdf`); + } + }; + + const getBillingPeriod = (billDetails) => { + const { taxPeriodFrom, taxPeriodTo, fromPeriod, toPeriod } = billDetails || {}; + if (taxPeriodFrom && taxPeriodTo) { + let from = new Date(taxPeriodFrom).getFullYear().toString(); + let to = new Date(taxPeriodTo).getFullYear().toString(); + return "FY " + from + "-" + to; + } else if (fromPeriod && toPeriod) { + if (workflw === "mcollect") { + let from = + new Date(fromPeriod).getDate().toString() + + " " + + Digit.Utils.date.monthNames[new Date(fromPeriod).getMonth() ].toString() + + " " + + new Date(fromPeriod).getFullYear().toString(); + let to = + new Date(toPeriod).getDate() + + " " + + Digit.Utils.date.monthNames[new Date(toPeriod).getMonth()] + + " " + + new Date(toPeriod).getFullYear(); + return from + " - " + to; + } + else if(workflw === "WNS") + { + let from = + new Date(fromPeriod).getDate().toString() + + "/" + + (new Date(fromPeriod).getMonth() + 1).toString() + + "/" + + new Date(fromPeriod).getFullYear().toString(); + let to = + new Date(toPeriod).getDate() + + "/" + + (new Date(toPeriod).getMonth() + 1) + + "/" + + new Date(toPeriod).getFullYear(); + return from + " - " + to; + } + let from = new Date(fromPeriod).getFullYear().toString(); + let to = new Date(toPeriod).getFullYear().toString(); + return "FY " + from + "-" + to; + } else return "N/A"; + }; + + let bannerText; + if (workflw) { + bannerText = `CITIZEN_SUCCESS_UC_PAYMENT_MESSAGE`; + } else { + if (paymentData?.paymentDetails?.[0]?.businessService && paymentData?.paymentDetails?.[0]?.businessService?.includes("BPA")) { + let nameOfAchitect = sessionStorage.getItem("BPA_ARCHITECT_NAME"); + let parsedArchitectName = nameOfAchitect ? JSON.parse(nameOfAchitect) : "ARCHITECT"; + bannerText = `CITIZEN_SUCCESS_${paymentData?.paymentDetails[0]?.businessService.replace(/\./g, "_")}_${parsedArchitectName}_PAYMENT_MESSAGE`; + } else if (business_service?.includes("WS") || business_service?.includes("SW")) { + bannerText = t(`CITIZEN_SUCCESS_${paymentData?.paymentDetails[0].businessService.replace(/\./g, "_")}_WS_PAYMENT_MESSAGE`); + } else { + bannerText = paymentData?.paymentDetails[0]?.businessService ? `CITIZEN_SUCCESS_${paymentData?.paymentDetails[0]?.businessService.replace(/\./g, "_")}_PAYMENT_MESSAGE` : t("CITIZEN_SUCCESS_UC_PAYMENT_MESSAGE"); + } + } + + // https://dev.digit.org/collection-services/payments/FSM.TRIP_CHARGES/_search?tenantId=pb.amritsar&consumerCodes=107-FSM-2021-02-18-063433 + + // if (billDataLoading) return ; + + const rowContainerStyle = { + padding: "4px 0px", + justifyContent: "space-between", + }; + //New Payment Reciept For PT module with year bifurcations + + const printRecieptNew = async (payment) => { + // console.log("paymentpayment",payment,payment.Payments[0].paymentDetails[0].receiptNumber,payment.Payments[0]) + const tenantId = Digit.ULBService.getCurrentTenantId(); + const state = Digit.ULBService.getStateId(); + let paymentArray=[]; + const payments = await Digit.PaymentService.getReciept(tenantId, "PT", { receiptNumbers: payment.Payments[0].paymentDetails[0].receiptNumber }); + let response = { filestoreIds: [payments.Payments[0]?.fileStoreId] }; + if (true) { + let assessmentYear="",assessmentYearForReceipt=""; + let count=0; + let toDate,fromDate; + if(payments.Payments[0].paymentDetails[0].businessService=="PT"){ + let arrearRow={}; let arrearArray=[]; + let taxRow={}; let taxArray=[]; + + + let roundoff=0,tax=0,firecess=0,cancercess=0,penalty=0,rebate=0,interest=0,usage_exemption=0,special_category_exemption=0,adhoc_penalty=0,adhoc_rebate=0,total=0; + let roundoffT=0,taxT=0,firecessT=0,cancercessT=0,penaltyT=0,rebateT=0,interestT=0,usage_exemptionT=0,special_category_exemptionT=0,adhoc_penaltyT=0,adhoc_rebateT=0,totalT=0; + + + payments.Payments[0].paymentDetails[0].bill.billDetails.map(element => { + + if(element.amount >0 || element.amountPaid>0) + { count=count+1; + toDate=convertEpochToDate(element.toPeriod).split("/")[2]; + fromDate=convertEpochToDate(element.fromPeriod).split("/")[2]; + assessmentYear=assessmentYear==""?fromDate+"-"+toDate+"(Rs."+element.amountPaid+")":assessmentYear+","+fromDate+"-"+toDate+"(Rs."+element.amountPaid+")"; + assessmentYearForReceipt=fromDate+"-"+toDate; + + element.billAccountDetails.map(ele => { + if(ele.taxHeadCode == "PT_TAX") + {tax=ele.adjustedAmount; + taxT=ele.amount} + else if(ele.taxHeadCode == "PT_TIME_REBATE") + {rebate=ele.adjustedAmount; + rebateT=ele.amount;} + else if(ele.taxHeadCode == "PT_CANCER_CESS") + {cancercess=ele.adjustedAmount; + cancercessT=ele.amount;} + else if(ele.taxHeadCode == "PT_FIRE_CESS") + {firecess=ele.adjustedAmount; + firecessT=ele.amount;} + else if(ele.taxHeadCode == "PT_TIME_INTEREST") + {interest=ele.adjustedAmount; + interestT=ele.amount;} + else if(ele.taxHeadCode == "PT_TIME_PENALTY") + {penalty=ele.adjustedAmount; + penaltyT=ele.amount;} + else if(ele.taxHeadCode == "PT_OWNER_EXEMPTION") + {special_category_exemption=ele.adjustedAmount; + special_category_exemptionT=ele.amount;} + else if(ele.taxHeadCode == "PT_ROUNDOFF") + {roundoff=ele.adjustedAmount; + roundoffT=ele.amount;} + else if(ele.taxHeadCode == "PT_UNIT_USAGE_EXEMPTION") + {usage_exemption=ele.adjustedAmount; + usage_exemptionT=ele.amount;} + else if(ele.taxHeadCode == "PT_ADHOC_PENALTY") + {adhoc_penalty=ele.adjustedAmount; + adhoc_penaltyT=ele.amount;} + else if(ele.taxHeadCode == "PT_ADHOC_REBATE") + {adhoc_rebate=ele.adjustedAmount; + adhoc_rebateT=ele.amount;} + + totalT=totalT+ele.amount; + }); + arrearRow={ + "year":assessmentYearForReceipt, + "tax":tax, + "firecess":firecess, + "cancercess":cancercess, + "penalty":penalty, + "rebate": rebate, + "interest":interest, + "usage_exemption":usage_exemption, + "special_category_exemption": special_category_exemption, + "adhoc_penalty":adhoc_penalty, + "adhoc_rebate":adhoc_rebate, + "roundoff":roundoff, + "total":element.amountPaid + }; + taxRow={ + "year":assessmentYearForReceipt, + "tax":taxT, + "firecess":firecessT, + "cancercess":cancercessT, + "penalty":penaltyT, + "rebate": rebateT, + "interest":interestT, + "usage_exemption":usage_exemptionT, + "special_category_exemption": special_category_exemptionT, + "adhoc_penalty":adhoc_penaltyT, + "adhoc_rebate":adhoc_rebateT, + "roundoff":roundoffT, + "total":element.amount + }; + arrearArray.push(arrearRow); + taxArray.push(taxRow); + } + + + }); + + if(count==0) + { + let toDate=convertEpochToDate( payments.Payments[0].paymentDetails[0].bill.billDetails[0].toPeriod).split("/")[2]; + let fromDate=convertEpochToDate( payments.Payments[0].paymentDetails[0].bill.billDetails[0].fromPeriod).split("/")[2]; + assessmentYear=assessmentYear==""?fromDate+"-"+toDate:assessmentYear+","+fromDate+"-"+toDate; + assessmentYearForReceipt=fromDate+"-"+toDate; + + + payloadReceiptDetails.Payments[0].paymentDetails[0].bill.billDetails[0].billAccountDetails.map(ele => { + + if(ele.taxHeadCode == "PT_TAX") + {tax=ele.adjustedAmount; + taxT=ele.amount} + else if(ele.taxHeadCode == "PT_TIME_REBATE") + {rebate=ele.adjustedAmount; + rebateT=ele.amount;} + else if(ele.taxHeadCode == "PT_CANCER_CESS") + {cancercess=ele.adjustedAmount; + cancercessT=ele.amount;} + else if(ele.taxHeadCode == "PT_FIRE_CESS") + {firecess=ele.adjustedAmount; + firecessT=ele.amount;} + else if(ele.taxHeadCode == "PT_TIME_INTEREST") + {interest=ele.adjustedAmount; + interestT=ele.amount;} + else if(ele.taxHeadCode == "PT_TIME_PENALTY") + {penalty=ele.adjustedAmount; + penaltyT=ele.amount;} + else if(ele.taxHeadCode == "PT_OWNER_EXEMPTION") + {special_category_exemption=ele.adjustedAmount; + special_category_exemptionT=ele.amount;} + else if(ele.taxHeadCode == "PT_ROUNDOFF") + {roundoff=ele.adjustedAmount; + roundoffT=ele.amount;} + else if(ele.taxHeadCode == "PT_UNIT_USAGE_EXEMPTION") + {usage_exemption=ele.adjustedAmount; + usage_exemptionT=ele.amount;} + else if(ele.taxHeadCode == "PT_ADHOC_PENALTY") + {adhoc_penalty=ele.adjustedAmount; + adhoc_penaltyT=ele.amount;} + else if(ele.taxHeadCode == "PT_ADHOC_REBATE") + {adhoc_rebate=ele.adjustedAmount; + adhoc_rebateT=ele.amount;} + + total=total+ele.adjustedAmount; + totalT=totalT+ele.amount; + + }); + arrearRow={ + "year":assessmentYearForReceipt, + "tax":tax, + "firecess":firecess, + "cancercess":cancercess, + "penalty":penalty, + "interest":interest, + "usage_exemption":usage_exemption, + "special_category_exemption": special_category_exemption, + "adhoc_penalty":adhoc_penalty, + "adhoc_rebate":adhoc_rebate, + "roundoff":roundoff, + "total": payloadReceiptDetails.Payments[0].paymentDetails[0].bill.billDetails[0].amountPaid + + }; + taxRow={ + "year":assessmentYearForReceipt, + "tax":taxT, + "firecess":firecessT, + "cancercess":cancercessT, + "penalty":penaltyT, + "rebate": rebateT, + "interest":interestT, + "usage_exemption":usage_exemptionT, + "special_category_exemption": special_category_exemptionT, + "adhoc_penalty":adhoc_penaltyT, + "adhoc_rebate":adhoc_rebateT, + "roundoff":roundoffT, + "total": payloadReceiptDetails.Payments[0].paymentDetails[0].bill.billDetails[0].amount + }; + arrearArray.push(arrearRow); + taxArray.push(taxRow); + + } + + const details = { + "assessmentYears": assessmentYear, + "arrearArray":arrearArray, + "taxArray": taxArray + } + payments.Payments[0].paymentDetails[0].additionalDetails=details; + + } + + paymentArray[0]=payments.Payments[0] + // console.log("payments",payments) + response = await Digit.PaymentService.generatePdf(state, { Payments: paymentArray }, generatePdfKey); + // console.log("responseresponse",response) + } + const fileStore = await Digit.PaymentService.printReciept(state, { fileStoreIds: response.filestoreIds[0] }); + window.open(fileStore[response.filestoreIds[0]], "_blank"); + }; + const ommitRupeeSymbol = ["PT"].includes(business_service); + + // if ((window.location.href.includes("bpa") || window.location.href.includes("BPA")) && isBpaSearchLoading) return + + return ( + + + + + } + message={t("CS_COMMON_PAYMENT_COMPLETE")} + info={t("CS_COMMON_RECIEPT_NO")} + applicationNumber={paymentData?.paymentDetails[0].receiptNumber} + successful={true} + /> + {t(`${bannerText}_DETAIL`)} + + + {/** TODO : move this key and value into the hook based on business Service */} + {(business_service === "PT" || workflw) && ( + + )} + + {(business_service === "PT" || workflw) && ( + + )} + + + + {(business_service !== "PT" || workflw) && ( + + )} + +
+ {business_service == "TL" ? ( +
+ + + + + {t("TL_RECEIPT")} +
+ ) : null} + {business_service == "TL" ? ( +
+ + + + + {t("TL_CERTIFICATE")} +
+ ) : null} + {/* {bpaData?.[0]?.businessService === "BPA_OC" && (bpaData?.[0]?.status==="APPROVED" || bpaData?.[0]?.status==="PENDING_SANC_FEE_PAYMENT") ? ( +
getPermitOccupancyOrderSearch("occupancy-certificate")}> + + {t("BPA_OC_CERTIFICATE")} +
+ ) : null} + {bpaData?.[0]?.businessService === "BPA_LOW" ? ( +
getPermitOccupancyOrderSearch("buildingpermit-low")}> + + {t("BPA_PERMIT_ORDER")} +
+ ) : null} + {bpaData?.[0]?.businessService === "BPA" && (bpaData?.[0]?.businessService !== "BPA_LOW") && (bpaData?.[0]?.businessService !== "BPA_OC") && (bpaData?.[0]?.status==="PENDING_SANC_FEE_PAYMENT" || bpaData?.[0]?.status==="APPROVED")? ( +
getPermitOccupancyOrderSearch("buildingpermit")}> + + {t("BPA_PERMIT_ORDER")} +
+ ) : null} */} +
+ {business_service?.includes("PT") &&
+ +
} + {business_service?.includes("PT") ? ( +
+ {t("CS_DOWNLOAD_RECEIPT")} +
+ ) : null} + {business_service?.includes("WS") ? ( +
+ {t("CS_DOWNLOAD_RECEIPT")} +
+ ) : null} + {business_service?.includes("WS") ? + + :null} + {business_service?.includes("SW") ? ( +
+ {t("CS_DOWNLOAD_RECEIPT")} +
+ ) : null} + {business_service?.includes("FSM") ? ( +
+ {t("CS_DOWNLOAD_RECEIPT")} +
+ ) : null} + {business_service?.includes("BPA") ? ( +
+ {t("CS_DOWNLOAD_RECEIPT")} +
+ ) : null} + {!(business_service == "TL") || !(business_service?.includes("PT")) && } + {!(business_service == "TL") || !(business_service?.includes("PT")) && ( +
+ {t("CORE_COMMON_GO_TO_HOME")} +
+ )} + {business_service == "TL" && ( + + + + )} +
+ ); +}; + +export const FailedPayment = (props) => { + // const { addParams, clearParams } = props; + const { t } = useTranslation(); + // const { consumerCode } = useParams(); + const {consumerCode} = Digit.Hooks.useQueryParams(); + const getMessage = () => "Failure !"; + return ( + + + {t("ES_COMMON_TRACK_COMPLAINT_TEXT")} + + ); +}; + diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/configs/OpenSearchConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/configs/OpenSearchConfig.js new file mode 100644 index 000000000..628cf3cbb --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/configs/OpenSearchConfig.js @@ -0,0 +1,192 @@ +export const OpenSearchConfig = { + "label": "OPEN_PAYMENT_SEARCH", + "type": "search", + "apiDetails": { + "serviceName": "/ws-services/wc/_search", + "requestParam": {}, + "requestBody": {}, + "minParametersForSearchForm": 2, + "masterName": "commonUiConfig", + "moduleName": "OpenPaymentSearch", + "tableFormJsonPath": "requestBody.pagination", + "filterFormJsonPath": "requestBody.custom", + "searchFormJsonPath": "requestBody.custom" + }, + "sections": { + "search": { + "uiConfig": { + "type":"search", + "headerLabel": "OPEN_PAYMENT_SEARCH", + "headerStyle": null, + "primaryLabel": "ES_COMMON_SEARCH", + "secondaryLabel": "ES_COMMON_CLEAR_SEARCH", + "minReqFields": 2, + "showFormInstruction": "OPEN_PAYMENT_SEARCH_HINT", + "defaultValues": { + "consumerCode": "" + }, + "fields": [ + { + label: "SELECT_TENANT", + type: "apidropdown", + isMandatory: false, + disable: false, + populators: { + "optionsCustomStyle": { + "top": "2.3rem", + "overflow":"auto", + "maxHeight":"400px" + }, + name: "tenantId", + optionsKey: "updatedCode", + allowMultiSelect: false, + masterName: "commonUiConfig", + moduleName: "OpenPaymentSearch", + customfn: "populateReqCriteria", + }, + }, + { + "label": "CONNECTION_ID", + "type": "text", + "isMandatory": false, + "disable": false, + "populators": { + "name": "consumerCode", + "style":{ + "marginBottom":"0px" + }, + "placeholder":"WS/7141/2024-25/****", + // "validation":{ + // "maxLength":"1" + // } + }, + }, + ] + }, + "label": "", + "children": {}, + "show": true + }, + "searchResult": { + "uiConfig": { + "columns": [ + { + "label": "OP_CONS_CODE", + "jsonPath": "connectionNo", + "additionalCustomization": true + }, + // { + // "label": "OP_BILL_NUM", + // "jsonPath": "billNumber", + // // "additionalCustomization": true + // }, + { + "label": "OP_PAYER_NAME", + "jsonPath": "connectionHolders[0].name", + "additionalCustomization": true + }, + { + "label": "OP_APPLICATION_TYPE", + "jsonPath": "applicationType", + "additionalCustomization": true + }, + { + "label": "OP_CONNECTION_TYPE", + "jsonPath": "connectionType", + "additionalCustomization": true + }, + { + "label": "OP_METER_ID", + "jsonPath": "meterId", + // "additionalCustomization": true + }, + { + "label": "OP_CONNECTION_OLD_ID", + "jsonPath": "oldConnectionNo", + // "additionalCustomization": true + }, + { + "label": "OP_METER_INSTALLATION_DATE", + "jsonPath": "meterInstallationDate", + "additionalCustomization": true + }, + { + "label": "OP_METER_READING_DATE", + "jsonPath": "previousReadingDate", + "additionalCustomization": true + }, + // { + // "label": "OP_PROPERTY_TYPE", + // "jsonPath": "additionalDetails.propertyType", + // "additionalCustomization": true + // }, + { + "label": "OP_APPLICATION_STATUS", + "jsonPath": "status", + "additionalCustomization": true + }, + // { + // "label": "OP_SERVICE_TYPE", + // "jsonPath": "connectionType", + // "additionalCustomization": true + // }, + // { + // "label": "OP_MOB_NO", + // "jsonPath": "mobileNumber", + // // "additionalCustomization": true + // }, + // { + // "label": "OP_BILL_DATE", + // "jsonPath": "billDate", + // "additionalCustomization": true + // }, + // { + // "label": "OP_BILL_TOTAL_AMT", + // "jsonPath": "totalAmount", + // "additionalCustomization": true + // }, + // { + // "label": "TQM_PLANT", + // "jsonPath": "plantCode", + // "additionalCustomization": false, + // "prefix": "PQM.PLANT_", + // "translate": true + // }, + // { + // "label": "TQM_TREATMENT_PROCESS", + // "jsonPath": "processCode", + // "additionalCustomization": false, + // "prefix": "PQM.Process_", + // "translate": true + // }, + // { + // "label": "TQM_TEST_TYPE", + // "jsonPath": "testType", + // "additionalCustomization": false, + // "prefix": "PQM.TestType_", + // "translate": true + // }, + // { + // "label": "ES_TQM_TEST_DATE", + // "jsonPath": "auditDetails.lastModifiedTime", + // "additionalCustomization": true + // }, + // { + // "label": "TQM_TEST_RESULTS", + // "jsonPath": "status", + // "additionalCustomization": true + // } + ], + // "showActionBarMobileCard": true, + // "actionButtonLabelMobileCard": "TQM_VIEW_RESULTS", + "enableGlobalSearch": false, + "enableColumnSort": true, + "resultsJsonPath": "WaterConnection", + "tableClassName":"table pqm-table" + }, + "children": {}, + "show": true + } + }, + "additionalSections": {} +} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/configs/UICustomizations.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/configs/UICustomizations.js new file mode 100644 index 000000000..2a8e0bd33 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/configs/UICustomizations.js @@ -0,0 +1,182 @@ +import { Link, useHistory } from "react-router-dom"; +import _ from "lodash"; +import React from "react"; + +function anonymizeHalfString(input) { + // Calculate the midpoint of the string + const midpoint = Math.ceil(input.length / 2); + + // Replace the first 50% of the string with asterisks + const anonymized = "*".repeat(midpoint) + input.substring(midpoint); + + return anonymized; +} + +export const UICustomizations = { + OpenPaymentSearch:{ + preProcess: (data, additionalDetails) => { + + //we need to get three things -> consumerCode,businessService,tenantId + // businessService and tenantId can be either in queryParams or in form + let {consumerCode,businessService,tenantId} = data?.state?.searchForm || {}; + businessService = businessService?.code + tenantId = tenantId?.[0]?.code + if(!businessService){ + businessService = additionalDetails?.queryParams?.businessService + } + if(!tenantId){ + tenantId = additionalDetails?.queryParams?.tenantId + } + const finalParams = { + // consumerCode, + tenantId, + businessService, + connectionNumber:consumerCode, + isOpenPaymentSearch:true + } + data.params = finalParams + // data.params.textSearch = finalParams.consumerCode + // const tenantId = Digit.ULBService.getCurrentTenantId(); + // data.body = { RequestInfo: data.body.RequestInfo }; + // const { limit, offset } = data?.state?.tableForm || {}; + // const { campaignName, campaignType } = data?.state?.searchForm || {}; + // data.body.CampaignDetails = { + // tenantId: tenantId, + // status: ["failed"], + // createdBy: Digit.UserService.getUser().info.uuid, + // pagination: { + // sortBy: "createdTime", + // sortOrder: "desc", + // limit: limit, + // offset: offset, + // }, + // }; + // if (campaignName) { + // data.body.CampaignDetails.campaignName = campaignName; + // } + // if (campaignType) { + // data.body.CampaignDetails.projectType = campaignType?.[0]?.code; + // } + delete data.body.custom; + delete data.body.pagination; + data.options = { + userService:false, + auth:false + } + // delete data.body.inbox; + // delete data.params; + return data; + }, + additionalCustomizations: (row, key, column, value, t, searchResult) => { + + switch (key) { + case "OP_CONS_CODE": + return + + {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} + + + + case "OP_APPLICATION_TYPE": + return
+ { value ? t(Digit.Utils.locale.getTransformedLocale(`OP_APPLICATION_TYPE_${value}`)) : t("ES_COMMON_NA")} +
+ + case "OP_APPLICATION_STATUS": + return
+ { value ? t(Digit.Utils.locale.getTransformedLocale(`OP_APPLICATION_STATUS_${value}`)) : t("ES_COMMON_NA")} +
+ case "OP_CONNECTION_TYPE": + return
+ { value ? t(Digit.Utils.locale.getTransformedLocale(`OP_CONNECTION_TYPE_${value}`)) : t("ES_COMMON_NA")} +
+ case "OP_METER_INSTALLATION_DATE": + return
+ {value ? Digit.DateUtils.ConvertEpochToDate(value) : t("ES_COMMON_NA")} +
+ case "OP_METER_READING_DATE": + return
+ {value ? Digit.DateUtils.ConvertEpochToDate(value) : t("ES_COMMON_NA")} +
+ case "OP_PROPERTY_TYPE": + return
+ { value ? t(Digit.Utils.locale.getTransformedLocale(`OP_PROPERTY_TYPE_${value}`)) : t("ES_COMMON_NA")} +
+ case "OP_PAYER_NAME": + return
+ {value ? anonymizeHalfString(value) : t("ES_COMMON_NA")} +
+ + + default: + return {t("ES_COMMON_DEFAULT_NA")} + } + if (key === "OP_BILL_DATE") { + return Digit.DateUtils.ConvertEpochToDate(value); + } + + if(key === "OP_BILL_TOTAL_AMT"){ + return {`₹ ${value}`} + } + + if(key === "OP_CONS_CODE") { + return + + {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} + + + } + }, + populateReqCriteria: () => { + const tenantId = Digit.ULBService.getCurrentTenantId(); + return { + url: "/mdms-v2/v1/_search", + params: { tenantId }, + body: { + MdmsCriteria: { + tenantId, + moduleDetails: [ + { + moduleName: "tenant", + masterDetails: [ + { + name: "tenants", + }, + ], + }, + ], + }, + }, + config: { + enabled: true, + select: (data) => { + const result = data?.MdmsRes?.tenant?.tenants?.filter(row => row?.divisionCode && row?.divisionName)?.map(row => { + return { + ...row, + updatedCode:`${row.divisionName} - ${row?.name}` + } + }); + return result; + }, + }, + }; + }, + customValidationCheck: (data) => { + + //checking both to and from date are present + const { consumerCode } = data; + if(!consumerCode) return false; + if(consumerCode.length < 10 || consumerCode.length > 25){ + return { warning: true, label: "ES_COMMON_ENTER_VALID_CONSUMER_CODE" }; + } + // if ((createdFrom === "" && createdTo !== "") || (createdFrom !== "" && createdTo === "")) + // return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" }; + + return false; + } + } +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/hooks/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/hooks/index.js new file mode 100644 index 000000000..1e5435e13 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/hooks/index.js @@ -0,0 +1,23 @@ +import utils from "../utils"; + +const payment = { + +}; + +const Hooks = { + payment, +}; + +const Utils = { + browser: { + sample: () => {}, + }, + payment:{ + ...utils + } +}; + +export const CustomisedHooks = { + Hooks, + Utils, +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/pages/citizen/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/pages/citizen/index.js new file mode 100644 index 000000000..afd0a64f9 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/pages/citizen/index.js @@ -0,0 +1,39 @@ +import React, { useEffect } from "react"; +import { Switch, useLocation,Route } from "react-router-dom"; +import { useTranslation } from "react-i18next"; +import { PrivateRoute, AppContainer, BreadCrumb,BackButton } from "@egovernments/digit-ui-react-components"; +import OpenSearch from "../../components/OpenSearch"; +import OpenView from "../../components/OpenView"; +import { SuccessfulPayment,FailedPayment } from "../../components/Response"; + + +const CitizenApp = ({ path }) => { + const { t } = useTranslation(); + const location = useLocation(); + const commonProps = { stateCode:"pb", cityCode:"pb.abianakhurd", moduleCode:"WS" }; + const excludeBackBtn = ["/response","/open-search","/success"] + + return ( + +
+ {!excludeBackBtn?.some(url => location.pathname.includes(url)) && {t("CS_COMMON_BACK")}} + +
In Open Payment Module
} /> + } /> + } /> + + + + + + +
+
+
+ ); +}; + +export default CitizenApp; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/utils/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/utils/index.js new file mode 100644 index 000000000..aed14ad04 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/utils/index.js @@ -0,0 +1,2 @@ +export const PRIMARY_COLOR = "#C84C0E"; +export default {} \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/utils/payGov.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/utils/payGov.js new file mode 100644 index 000000000..00f2d0339 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/payment/src/utils/payGov.js @@ -0,0 +1,18 @@ +export const makePayment =async(url,data)=>{ + var myHeaders = new Headers(); +myHeaders.append("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"); +myHeaders.append("Access-Control-Allow-Origin", "*"); + +var requestOptions = { +method: 'POST', +headers: myHeaders, +body: data, +"mode": "no-cors", +redirect: 'follow' +}; + +fetch(url, requestOptions) +.then(response => response.text()) +.then(result => console.log(result)) +.catch(error => console.log('error', error)); +} \ No newline at end of file diff --git a/frontend/micro-ui/web/package.json b/frontend/micro-ui/web/package.json index 038d7fd10..bcaba2048 100644 --- a/frontend/micro-ui/web/package.json +++ b/frontend/micro-ui/web/package.json @@ -18,10 +18,11 @@ "@egovernments/digit-ui-libraries": "1.5.7", "@egovernments/digit-ui-module-dss": "1.5.34", "@egovernments/digit-ui-module-core": "1.5.46", - "@egovernments/digit-ui-css": "1.5.50", + "@egovernments/digit-ui-css": "1.5.54", "@egovernments/digit-ui-module-hrms": "1.5.27", "@egovernments/digit-ui-module-pgr": "1.7.0", "@egovernments/digit-ui-module-engagement": "1.5.20", + "@egovernments/digit-ui-module-payment":"0.0.14", "@egovernments/digit-ui-react-components": "1.5.26", "babel-loader": "8.1.0", "clean-webpack-plugin": "4.0.0", diff --git a/frontend/micro-ui/web/public/index.html b/frontend/micro-ui/web/public/index.html index 2561ac4d5..9ed7c0982 100644 --- a/frontend/micro-ui/web/public/index.html +++ b/frontend/micro-ui/web/public/index.html @@ -7,7 +7,11 @@ + + + + mSeva diff --git a/frontend/micro-ui/web/src/App.js b/frontend/micro-ui/web/src/App.js index d5aa1a95c..e30eddafd 100644 --- a/frontend/micro-ui/web/src/App.js +++ b/frontend/micro-ui/web/src/App.js @@ -5,6 +5,7 @@ import { DigitUI } from "@egovernments/digit-ui-module-core"; import { UICustomizations } from "./Customisations/UICustomizations"; import { initDSSComponents } from "@egovernments/digit-ui-module-dss"; import { initEngagementComponents } from "@egovernments/digit-ui-module-engagement"; +import {initPaymentComponents} from "@egovernments/digit-ui-module-payment"; import { initPGRComponents, PGRReducers, @@ -20,6 +21,7 @@ const enabledModules = [ "HRMS", "Engagement", "PGR", + "Payment" ]; const moduleReducers = (initData) => ({ @@ -36,6 +38,7 @@ const initDigitUI = () => { initDSSComponents(); initEngagementComponents(); initPGRComponents(); + initPaymentComponents(); }; initLibraries().then(() => { diff --git a/frontend/micro-ui/web/src/Customisations/UICustomizations.js b/frontend/micro-ui/web/src/Customisations/UICustomizations.js index 6d17ab0d5..042175868 100644 --- a/frontend/micro-ui/web/src/Customisations/UICustomizations.js +++ b/frontend/micro-ui/web/src/Customisations/UICustomizations.js @@ -425,4 +425,170 @@ export const UICustomizations = { } } }, + OpenPaymentSearch:{ + preProcess: (data, additionalDetails) => { + + //we need to get three things -> consumerCode,businessService,tenantId + // businessService and tenantId can be either in queryParams or in form + let {consumerCode,businessService,tenantId} = data?.state?.searchForm || {}; + businessService = businessService?.code + tenantId = tenantId?.[0]?.code + if(!businessService){ + businessService = additionalDetails?.queryParams?.businessService + } + if(!tenantId){ + tenantId = additionalDetails?.queryParams?.tenantId + } + const finalParams = { + // consumerCode, + tenantId, + businessService, + connectionNumber:consumerCode, + isOpenPaymentSearch:true + } + data.params = finalParams + // data.params.textSearch = finalParams.consumerCode + // const tenantId = Digit.ULBService.getCurrentTenantId(); + // data.body = { RequestInfo: data.body.RequestInfo }; + // const { limit, offset } = data?.state?.tableForm || {}; + // const { campaignName, campaignType } = data?.state?.searchForm || {}; + // data.body.CampaignDetails = { + // tenantId: tenantId, + // status: ["failed"], + // createdBy: Digit.UserService.getUser().info.uuid, + // pagination: { + // sortBy: "createdTime", + // sortOrder: "desc", + // limit: limit, + // offset: offset, + // }, + // }; + // if (campaignName) { + // data.body.CampaignDetails.campaignName = campaignName; + // } + // if (campaignType) { + // data.body.CampaignDetails.projectType = campaignType?.[0]?.code; + // } + delete data.body.custom; + delete data.body.pagination; + data.options = { + userService:false, + auth:false + } + // delete data.body.inbox; + // delete data.params; + return data; + }, + additionalCustomizations: (row, key, column, value, t, searchResult) => { + + switch (key) { + case "OP_CONS_CODE": + return + + {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} + + + + case "OP_APPLICATION_TYPE": + return
+ { value ? t(Digit.Utils.locale.getTransformedLocale(`OP_APPLICATION_TYPE_${value}`)) : t("ES_COMMON_NA")} +
+ + case "OP_APPLICATION_STATUS": + return
+ { value ? t(Digit.Utils.locale.getTransformedLocale(`OP_APPLICATION_STATUS_${value}`)) : t("ES_COMMON_NA")} +
+ case "OP_CONNECTION_TYPE": + return
+ { value ? t(Digit.Utils.locale.getTransformedLocale(`OP_CONNECTION_TYPE_${value}`)) : t("ES_COMMON_NA")} +
+ case "OP_METER_INSTALLATION_DATE": + return
+ {value ? Digit.DateUtils.ConvertEpochToDate(value) : t("ES_COMMON_NA")} +
+ case "OP_METER_READING_DATE": + return
+ {value ? Digit.DateUtils.ConvertEpochToDate(value) : t("ES_COMMON_NA")} +
+ case "OP_PROPERTY_TYPE": + return
+ { value ? t(Digit.Utils.locale.getTransformedLocale(`OP_PROPERTY_TYPE_${value}`)) : t("ES_COMMON_NA")} +
+ case "OP_PAYER_NAME": + return
+ {value ? anonymizeHalfString(value) : t("ES_COMMON_NA")} +
+ + + default: + return {t("ES_COMMON_DEFAULT_NA")} + } + if (key === "OP_BILL_DATE") { + return Digit.DateUtils.ConvertEpochToDate(value); + } + + if(key === "OP_BILL_TOTAL_AMT"){ + return {`₹ ${value}`} + } + + if(key === "OP_CONS_CODE") { + return + + {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} + + + } + }, + populateReqCriteria: () => { + const tenantId = Digit.ULBService.getCurrentTenantId(); + return { + url: "/mdms-v2/v1/_search", + params: { tenantId }, + body: { + MdmsCriteria: { + tenantId, + moduleDetails: [ + { + moduleName: "tenant", + masterDetails: [ + { + name: "tenants", + }, + ], + }, + ], + }, + }, + config: { + enabled: true, + select: (data) => { + const result = data?.MdmsRes?.tenant?.tenants?.filter(row => row?.divisionCode && row?.divisionName)?.map(row => { + return { + ...row, + updatedCode:`${row.divisionName} - ${row?.name}` + } + }); + return result; + }, + }, + }; + }, + customValidationCheck: (data) => { + + //checking both to and from date are present + const { consumerCode } = data; + if(!consumerCode) return false; + if(consumerCode.length < 10 || consumerCode.length > 25){ + return { warning: true, label: "ES_COMMON_ENTER_VALID_CONSUMER_CODE" }; + } + // if ((createdFrom === "" && createdTo !== "") || (createdFrom !== "" && createdTo === "")) + // return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" }; + + return false; + } + } }; diff --git a/municipal-services/property-services/src/main/java/org/egov/pt/config/PropertyConfiguration.java b/municipal-services/property-services/src/main/java/org/egov/pt/config/PropertyConfiguration.java index 7eb520b6a..5e1241895 100644 --- a/municipal-services/property-services/src/main/java/org/egov/pt/config/PropertyConfiguration.java +++ b/municipal-services/property-services/src/main/java/org/egov/pt/config/PropertyConfiguration.java @@ -354,4 +354,10 @@ public MappingJackson2HttpMessageConverter jacksonConverter(ObjectMapper objectM @Value("${inbox.property.search.allowed}") private Boolean isInboxSearchAllowed; + @Value("${egov.indexer.es.username}") + private String esUsername; + + @Value("${egov.indexer.es.password}") + private String esPassword; + } \ No newline at end of file diff --git a/municipal-services/property-services/src/main/java/org/egov/pt/repository/ElasticSearchRepository.java b/municipal-services/property-services/src/main/java/org/egov/pt/repository/ElasticSearchRepository.java index 0dbeec52f..d28d18d76 100644 --- a/municipal-services/property-services/src/main/java/org/egov/pt/repository/ElasticSearchRepository.java +++ b/municipal-services/property-services/src/main/java/org/egov/pt/repository/ElasticSearchRepository.java @@ -15,6 +15,11 @@ import org.springframework.web.client.RestTemplate; import java.util.List; +import org.springframework.context.annotation.Primary; +import javax.net.ssl.*; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Base64; @Component public class ElasticSearchRepository { @@ -24,15 +29,13 @@ public class ElasticSearchRepository { private FuzzySearchQueryBuilder queryBuilder; - private RestTemplate restTemplate; private ObjectMapper mapper; @Autowired - public ElasticSearchRepository(PropertyConfiguration config, FuzzySearchQueryBuilder queryBuilder, RestTemplate restTemplate, ObjectMapper mapper) { + public ElasticSearchRepository(PropertyConfiguration config, FuzzySearchQueryBuilder queryBuilder, ObjectMapper mapper) { this.config = config; this.queryBuilder = queryBuilder; - this.restTemplate = restTemplate; this.mapper = mapper; } @@ -52,10 +55,13 @@ public Object fuzzySearchProperties(PropertyCriteria criteria, List uuid HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); + headers.add("Authorization", getESEncodedCredentials()); + final HttpEntity entity = new HttpEntity( headers); + // response = restTemplate.exchange(url.toString(), HttpMethod.GET, entity, Map.class); HttpEntity requestEntity = new HttpEntity<>(searchQuery, headers); ResponseEntity response = null; try { - response = restTemplate.postForEntity(url, requestEntity, Object.class); + response = this.restTemplate().postForEntity(url, requestEntity, Object.class); } catch (Exception e) { e.printStackTrace(); @@ -80,7 +86,45 @@ private String getESURL() { return builder.toString(); } + public String getESEncodedCredentials() { + String credentials = config.getEsUsername() + ":" + config.getEsPassword(); + byte[] credentialsBytes = credentials.getBytes(); + byte[] base64CredentialsBytes = Base64.getEncoder().encode(credentialsBytes); + return "Basic " + new String(base64CredentialsBytes); + } + public static void trustSelfSignedSSL() { + try { + SSLContext ctx = SSLContext.getInstance("TLS"); + X509TrustManager tm = new X509TrustManager() { + public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException { + } + + public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException { + } + + public X509Certificate[] getAcceptedIssuers() { + return null; + } + }; + ctx.init(null, new TrustManager[]{tm}, null); + SSLContext.setDefault(ctx); + + // Disable hostname verification + HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { + public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) { + return true; + } + }); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + @Primary + public RestTemplate restTemplate() { + trustSelfSignedSSL(); + return new RestTemplate(); + } } diff --git a/municipal-services/property-services/src/main/resources/application.properties b/municipal-services/property-services/src/main/resources/application.properties index bce5a957f..759f658ea 100644 --- a/municipal-services/property-services/src/main/resources/application.properties +++ b/municipal-services/property-services/src/main/resources/application.properties @@ -198,6 +198,8 @@ state.level.tenant.id=pb #Elastic search properties elasticsearch.host=http://localhost:9200/ elasticsearch.search.endpoint=/_search +egov.indexer.es.username=elastic +egov.indexer.es.password=8fwbD6HbJh6HU0oddsHm8TEI property.es.index=property-services pt.search.name.fuziness=2 diff --git a/municipal-services/ws-calculator/src/main/java/org/egov/wscalculation/config/WSCalculationConfiguration.java b/municipal-services/ws-calculator/src/main/java/org/egov/wscalculation/config/WSCalculationConfiguration.java index a466bdb3e..44a44c116 100644 --- a/municipal-services/ws-calculator/src/main/java/org/egov/wscalculation/config/WSCalculationConfiguration.java +++ b/municipal-services/ws-calculator/src/main/java/org/egov/wscalculation/config/WSCalculationConfiguration.java @@ -270,4 +270,7 @@ public class WSCalculationConfiguration { @Value("${ws.generate.demand.bulk}") private String wsGenerateDemandBulktopic; + + @Value("${kafka.topic.roll.out.dashboard}") + private String rollOutDashBoardTopic; } diff --git a/municipal-services/ws-calculator/src/main/java/org/egov/wscalculation/service/WSCalculationService.java b/municipal-services/ws-calculator/src/main/java/org/egov/wscalculation/service/WSCalculationService.java index e5cd8cc61..216a1bc87 100644 --- a/municipal-services/ws-calculator/src/main/java/org/egov/wscalculation/service/WSCalculationService.java +++ b/municipal-services/ws-calculator/src/main/java/org/egov/wscalculation/service/WSCalculationService.java @@ -3,9 +3,7 @@ import java.util.List; import org.egov.common.contract.request.RequestInfo; -import org.egov.wscalculation.web.models.BulkDemand; -import org.egov.wscalculation.web.models.Calculation; -import org.egov.wscalculation.web.models.CalculationReq; +import org.egov.wscalculation.web.models.*; public interface WSCalculationService { @@ -15,4 +13,6 @@ public interface WSCalculationService { void generateDemandBasedOnTimePeriod(RequestInfo requestInfo, boolean isSendMessage); void generateBulkDemandForTenant(BulkDemand bulkDemand); + + RollOutDashboard sendDataForRollOut(RollOutDashboardRequest rollOutDashboardRequest); } diff --git a/municipal-services/ws-calculator/src/main/java/org/egov/wscalculation/service/WSCalculationServiceImpl.java b/municipal-services/ws-calculator/src/main/java/org/egov/wscalculation/service/WSCalculationServiceImpl.java index e6d7c5b91..701bc281d 100644 --- a/municipal-services/ws-calculator/src/main/java/org/egov/wscalculation/service/WSCalculationServiceImpl.java +++ b/municipal-services/ws-calculator/src/main/java/org/egov/wscalculation/service/WSCalculationServiceImpl.java @@ -3,11 +3,7 @@ import java.math.BigDecimal; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; import com.fasterxml.jackson.core.type.TypeReference; @@ -29,6 +25,7 @@ import org.egov.wscalculation.util.CalculatorUtil; import org.egov.wscalculation.util.WSCalculationUtil; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataRetrievalFailureException; import org.springframework.stereotype.Service; import com.jayway.jsonpath.JsonPath; @@ -457,6 +454,24 @@ public List applyAdhocTax(AdhocTaxReq adhocTaxReq) { } + @Override + public RollOutDashboard sendDataForRollOut(RollOutDashboardRequest rollOutDashboardRequest) { + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + LocalDateTime date = LocalDateTime.now(); + log.info("Time schedule start for roll out dashboard on : " + date.format(dateTimeFormatter)); + try { + String tenantId = rollOutDashboardRequest.getRollOutDashboard().getTenantid(); + if (tenantId != null) { + rollOutDashboardRequest.getRollOutDashboard().setCreatedTime(new Date()); + log.info("Role out data sending to kafka topic "+ rollOutDashboardRequest.getRollOutDashboard()); + wsCalculationProducer.push(config.getRollOutDashBoardTopic(), rollOutDashboardRequest.getRollOutDashboard()); + } + } catch (Exception e) { + log.info("Exception occurred while fetching tenantId"); + throw new DataRetrievalFailureException("Data not found "+e); + } + return rollOutDashboardRequest.getRollOutDashboard(); + } } diff --git a/municipal-services/ws-calculator/src/main/java/org/egov/wscalculation/web/controller/CalculatorController.java b/municipal-services/ws-calculator/src/main/java/org/egov/wscalculation/web/controller/CalculatorController.java index 2e15735ed..6de67bd0b 100644 --- a/municipal-services/ws-calculator/src/main/java/org/egov/wscalculation/web/controller/CalculatorController.java +++ b/municipal-services/ws-calculator/src/main/java/org/egov/wscalculation/web/controller/CalculatorController.java @@ -4,6 +4,7 @@ import java.util.List; import javax.validation.Valid; +import lombok.extern.slf4j.Slf4j; import org.egov.wscalculation.web.models.*; import org.egov.wscalculation.service.DemandService; @@ -24,7 +25,7 @@ import lombok.Getter; import lombok.Setter; - +@Slf4j @Getter @Setter @Builder @@ -113,4 +114,15 @@ public ResponseEntity addPenalty(@RequestBody Penalt } + @PostMapping("/_rollOutDashboardSearch") + public ResponseEntity rollOutDashboardSearch(@RequestBody RollOutDashboardRequest rollOutDashboardRequest) + { + log.info("Roll out dashboard request"+rollOutDashboardRequest.getRollOutDashboard()); + RollOutDashboard sendDataForRollOut=wSCalculationService.sendDataForRollOut(rollOutDashboardRequest); + RollOutDashboardResponse response = RollOutDashboardResponse.builder(). + rollOutDashboard(sendDataForRollOut).build(); + + return new ResponseEntity<>(response,HttpStatus.OK); + } + } diff --git a/municipal-services/ws-calculator/src/main/java/org/egov/wscalculation/web/models/RollOutDashboard.java b/municipal-services/ws-calculator/src/main/java/org/egov/wscalculation/web/models/RollOutDashboard.java new file mode 100644 index 000000000..53f40a94f --- /dev/null +++ b/municipal-services/ws-calculator/src/main/java/org/egov/wscalculation/web/models/RollOutDashboard.java @@ -0,0 +1,42 @@ +package org.egov.wscalculation.web.models; + +import jdk.nashorn.internal.ir.annotations.Ignore; +import lombok.*; + +import java.time.LocalDateTime; +import java.util.Date; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class RollOutDashboard { + private String id; + private String tenantid; + private String projectcode; + private String zone; + private String circle; + private String division; + private String subdivision; + private String section; + private int activeUsersCount; + private double totalAdvance; + private double totalPenalty; + private int totalConnections; + private int activeConnections; + private String lastDemandGenDate; + private int demandGeneratedConsumerCount; + private double totalDemandAmount; + private double collectionTillDate; + private String lastCollectionDate; + private int expenseCount; + private int countOfElectricityExpenseBills; + private int noOfPaidExpenseBills; + private String lastExpenseTxnDate; + private double totalAmountOfExpenseBills; + private double totalAmountOfElectricityBills; + private double totalAmountOfPaidExpenseBills; + private String dateRange; + private Date createdTime; + private String tenantName; +} \ No newline at end of file diff --git a/municipal-services/ws-calculator/src/main/java/org/egov/wscalculation/web/models/RollOutDashboardRequest.java b/municipal-services/ws-calculator/src/main/java/org/egov/wscalculation/web/models/RollOutDashboardRequest.java new file mode 100644 index 000000000..21f6f26fc --- /dev/null +++ b/municipal-services/ws-calculator/src/main/java/org/egov/wscalculation/web/models/RollOutDashboardRequest.java @@ -0,0 +1,24 @@ +package org.egov.wscalculation.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; + +import javax.validation.Valid; + +@AllArgsConstructor +@NoArgsConstructor +@Data +@Builder +public class RollOutDashboardRequest { + + @JsonProperty("RequestInfo") + private RequestInfo requestInfo = null; + + @Valid + @JsonProperty("rollOutDashboard") + private RollOutDashboard rollOutDashboard = null; +} \ No newline at end of file diff --git a/municipal-services/ws-calculator/src/main/java/org/egov/wscalculation/web/models/RollOutDashboardResponse.java b/municipal-services/ws-calculator/src/main/java/org/egov/wscalculation/web/models/RollOutDashboardResponse.java new file mode 100644 index 000000000..ca36edaff --- /dev/null +++ b/municipal-services/ws-calculator/src/main/java/org/egov/wscalculation/web/models/RollOutDashboardResponse.java @@ -0,0 +1,26 @@ +package org.egov.wscalculation.web.models; + + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; + +import javax.validation.Valid; +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class RollOutDashboardResponse { + + @JsonProperty("ResponseInfo") + private ResponseInfo responseInfo = null; + + @JsonProperty("RollOutDashboard") + private RollOutDashboard rollOutDashboard = null; + +} \ No newline at end of file diff --git a/municipal-services/ws-calculator/src/main/resources/application.properties b/municipal-services/ws-calculator/src/main/resources/application.properties index b1fd3f568..86620d15d 100644 --- a/municipal-services/ws-calculator/src/main/resources/application.properties +++ b/municipal-services/ws-calculator/src/main/resources/application.properties @@ -25,6 +25,7 @@ spring.kafka.producer.value-serializer=org.springframework.kafka.support.seriali $KAFKA TOPIC DETAILS egov.watercalculatorservice.createdemand.topic=ws-generate-demand +kafka.topic.roll.out.dashboard=rollout-dashboard-index #Demand Saved And Failed Topic ws.calculator.demand.successful.topic=ws-demand-saved diff --git a/municipal-services/ws-services/src/main/java/org/egov/waterconnection/config/WSConfiguration.java b/municipal-services/ws-services/src/main/java/org/egov/waterconnection/config/WSConfiguration.java index 1ee4ced6d..7f418bd30 100644 --- a/municipal-services/ws-services/src/main/java/org/egov/waterconnection/config/WSConfiguration.java +++ b/municipal-services/ws-services/src/main/java/org/egov/waterconnection/config/WSConfiguration.java @@ -277,6 +277,12 @@ public class WSConfiguration { @Value("${egov.es.search.endpoint}") private String esSearchEndpoint; + @Value("${egov.indexer.es.username}") + private String esUsername; + + @Value("${egov.indexer.es.password}") + private String esPassword; + @Value("${egov.ws.search.name.fuziness}") private String nameFuziness; diff --git a/municipal-services/ws-services/src/main/java/org/egov/waterconnection/repository/ElasticSearchRepository.java b/municipal-services/ws-services/src/main/java/org/egov/waterconnection/repository/ElasticSearchRepository.java index dfca87fa5..4042ef5a1 100644 --- a/municipal-services/ws-services/src/main/java/org/egov/waterconnection/repository/ElasticSearchRepository.java +++ b/municipal-services/ws-services/src/main/java/org/egov/waterconnection/repository/ElasticSearchRepository.java @@ -1,22 +1,33 @@ package org.egov.waterconnection.repository; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; import java.util.List; +import java.util.Base64; import org.egov.tracer.model.CustomException; import org.egov.waterconnection.config.WSConfiguration; import org.egov.waterconnection.repository.builder.FuzzySearchQueryBuilder; import org.egov.waterconnection.web.models.SearchCriteria; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; -import org.springframework.web.client.RestTemplate; import com.fasterxml.jackson.databind.ObjectMapper; +import javax.net.ssl.*; + +import org.springframework.web.client.RestTemplate; import lombok.extern.slf4j.Slf4j; + +import javax.net.ssl.*; + @Slf4j @Component public class ElasticSearchRepository { @@ -26,15 +37,14 @@ public class ElasticSearchRepository { private FuzzySearchQueryBuilder queryBuilder; - private RestTemplate restTemplate; private ObjectMapper mapper; + @Autowired - public ElasticSearchRepository(WSConfiguration config, FuzzySearchQueryBuilder queryBuilder, RestTemplate restTemplate, ObjectMapper mapper) { + public ElasticSearchRepository(WSConfiguration config, FuzzySearchQueryBuilder queryBuilder, ObjectMapper mapper) { this.config = config; this.queryBuilder = queryBuilder; - this.restTemplate = restTemplate; this.mapper = mapper; } @@ -54,10 +64,13 @@ public Object fuzzySearchProperties(SearchCriteria criteria, List ids) { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); + headers.add("Authorization", getESEncodedCredentials()); + final HttpEntity entity = new HttpEntity( headers); + // response = restTemplate.exchange(url.toString(), HttpMethod.GET, entity, Map.class); HttpEntity requestEntity = new HttpEntity<>(searchQuery, headers); ResponseEntity response = null; try { - response = restTemplate.postForEntity(url, requestEntity, Object.class); + response = this.restTemplate().postForEntity(url, requestEntity, Object.class); } catch (Exception e) { log.error("Failed to fetch data from ES: "+e.getMessage()); @@ -82,7 +95,44 @@ private String getESURL() { return builder.toString(); } + public String getESEncodedCredentials() { + String credentials = config.getEsUsername() + ":" + config.getEsPassword(); + byte[] credentialsBytes = credentials.getBytes(); + byte[] base64CredentialsBytes = Base64.getEncoder().encode(credentialsBytes); + return "Basic " + new String(base64CredentialsBytes); + } + public static void trustSelfSignedSSL() { + try { + SSLContext ctx = SSLContext.getInstance("TLS"); + X509TrustManager tm = new X509TrustManager() { + public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException { + } + + public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException { + } + + public X509Certificate[] getAcceptedIssuers() { + return null; + } + }; + ctx.init(null, new TrustManager[]{tm}, null); + SSLContext.setDefault(ctx); + + // Disable hostname verification + HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { + public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) { + return true; + } + }); + } catch (Exception ex) { + ex.printStackTrace(); + } + } - + @Primary + public RestTemplate restTemplate() { + trustSelfSignedSSL(); + return new RestTemplate(); + } } diff --git a/municipal-services/ws-services/src/main/java/org/egov/waterconnection/repository/WaterDaoImpl.java b/municipal-services/ws-services/src/main/java/org/egov/waterconnection/repository/WaterDaoImpl.java index c95a6aa18..84f89fff7 100644 --- a/municipal-services/ws-services/src/main/java/org/egov/waterconnection/repository/WaterDaoImpl.java +++ b/municipal-services/ws-services/src/main/java/org/egov/waterconnection/repository/WaterDaoImpl.java @@ -49,6 +49,9 @@ @Repository public class WaterDaoImpl implements WaterDao { + @Autowired + private DemandNotGeneratedRowMapper demandNotGeneratedRowMapper; + @Autowired private InactiveConsumerReportRowMapper inactiveConsumerReportRowMapper; @Autowired @@ -665,4 +668,18 @@ public List getInactiveConsumerReport(Long monthStar inactiveConsumerReportList=jdbcTemplate.query(inactive_consumer_query.toString(), preparedStatement.toArray(),inactiveConsumerReportRowMapper); return inactiveConsumerReportList; } + + public List getConsumersByPreviousMeterReading(Long previousMeterReading, String tenantId) + { + StringBuilder query=new StringBuilder(wsQueryBuilder.DEMAND_NOT_GENERATED_QUERY); + + List preparedStatement=new ArrayList<>(); + preparedStatement.add(tenantId); + preparedStatement.add(previousMeterReading); + preparedStatement.add(tenantId); + + log.info("Query for consumer demand not generated "+ query +" prepared statement "+ preparedStatement); + List consumersDemandNotGeneratedList=jdbcTemplate.query(query.toString(),preparedStatement.toArray(),demandNotGeneratedRowMapper); + return consumersDemandNotGeneratedList; + } } diff --git a/municipal-services/ws-services/src/main/java/org/egov/waterconnection/repository/builder/WsQueryBuilder.java b/municipal-services/ws-services/src/main/java/org/egov/waterconnection/repository/builder/WsQueryBuilder.java index 1a6c8d9e1..58ec99739 100644 --- a/municipal-services/ws-services/src/main/java/org/egov/waterconnection/repository/builder/WsQueryBuilder.java +++ b/municipal-services/ws-services/src/main/java/org/egov/waterconnection/repository/builder/WsQueryBuilder.java @@ -23,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.web.client.RestTemplate; @@ -168,6 +169,13 @@ public class WsQueryBuilder { + " connectionno IN (SELECT distinct connectionno FROM eg_ws_connection WHERE status='Inactive' AND" + " lastmodifiedtime >= ? AND lastmodifiedtime <= ? AND tenantid=?) " + " order by connectionno,lastmodifiedtime desc"; + + public static final String DEMAND_NOT_GENERATED_QUERY="select distinct conn.connectionno as connectionno from eg_ws_connection conn " + + "INNER JOIN eg_ws_service wc ON wc.connection_id = conn.id WHERE conn.status='Active' " + + "AND conn.tenantid=? and wc.connectiontype='Non_Metered' and conn.previousreadingdate=? and connectionno NOT IN " + + "(select distinct consumercode from egbs_demand_v1 d inner join egbs_demanddetail_v1 dd on dd.demandid = d.id " + + "where dd.taxheadcode='10101' and d.status ='ACTIVE' and d.businessservice='WS' and " + + "d.tenantid=?) order by connectionno;"; /** * @@ -281,25 +289,40 @@ public StringBuilder applyFilters(StringBuilder query, List preparedStat preparedStatement.add(criteria.getOldConnectionNumber()); } - if (!StringUtils.isEmpty(criteria.getConnectionNumber()) || !StringUtils.isEmpty(criteria.getTextSearch())) { - addClauseIfRequired(preparedStatement, query); - - if(!StringUtils.isEmpty(criteria.getConnectionNumber())) { - query.append(" conn.connectionno ~* ? "); - preparedStatement.add(criteria.getConnectionNumber()); - } - else { - query.append(" conn.connectionno ~* ? "); - preparedStatement.add(criteria.getTextSearch()); + if(ObjectUtils.isEmpty(criteria.getIsOpenPaymentSearch()) || !criteria.getIsOpenPaymentSearch()) { + + if (!StringUtils.isEmpty(criteria.getConnectionNumber()) || !StringUtils.isEmpty(criteria.getTextSearch())) { + addClauseIfRequired(preparedStatement, query); + + if (!StringUtils.isEmpty(criteria.getConnectionNumber())) { + query.append(" conn.connectionno ~* ? "); + preparedStatement.add(criteria.getConnectionNumber()); + } else { + query.append(" conn.connectionno ~* ? "); + preparedStatement.add(criteria.getTextSearch()); + } + + + if (!CollectionUtils.isEmpty(criteria.getConnectionNoSet())) { + query.append(" or conn.connectionno in (").append(createQuery(criteria.getConnectionNoSet())).append(" )"); + addToPreparedStatement(preparedStatement, criteria.getConnectionNoSet()); + } } - + } else { - if(!CollectionUtils.isEmpty(criteria.getConnectionNoSet())) { - query.append(" or conn.connectionno in (").append(createQuery(criteria.getConnectionNoSet())).append(" )"); - addToPreparedStatement(preparedStatement, criteria.getConnectionNoSet()); + if (!StringUtils.isEmpty(criteria.getConnectionNumber())){ + addClauseIfRequired(preparedStatement, query); + query.append(" conn.connectionno = ? "); + preparedStatement.add(criteria.getConnectionNumber()); } } + if (!CollectionUtils.isEmpty(criteria.getConnectionNoSet())) { + addClauseIfRequired(preparedStatement, query); + query.append(" conn.connectionno in (").append(createQuery(criteria.getConnectionNoSet())).append(" )"); + addToPreparedStatement(preparedStatement, criteria.getConnectionNoSet()); + } + if (!StringUtils.isEmpty(criteria.getStatus())) { addClauseIfRequired(preparedStatement, query); query.append(" conn.status = ? "); @@ -654,6 +677,16 @@ public StringBuilder applyFiltersForPlaneSearch(StringBuilder query, List=? "); + preparedStatement.add(criteria.getFromDate()); + } + if(criteria.getToDate()!=null){ + addClauseIfRequired(preparedStatement, query); + query.append(" conn.createdtime<=?"); + preparedStatement.add(criteria.getToDate()); + } } return query; } diff --git a/municipal-services/ws-services/src/main/java/org/egov/waterconnection/repository/rowmapper/DemandNotGeneratedRowMapper.java b/municipal-services/ws-services/src/main/java/org/egov/waterconnection/repository/rowmapper/DemandNotGeneratedRowMapper.java new file mode 100644 index 000000000..d42e53595 --- /dev/null +++ b/municipal-services/ws-services/src/main/java/org/egov/waterconnection/repository/rowmapper/DemandNotGeneratedRowMapper.java @@ -0,0 +1,26 @@ +package org.egov.waterconnection.repository.rowmapper; + +import org.egov.waterconnection.web.models.ConsumersDemandNotGenerated; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.ResultSetExtractor; +import org.springframework.stereotype.Component; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +@Component +public class DemandNotGeneratedRowMapper implements ResultSetExtractor> { + @Override + public List extractData(ResultSet resultSet) throws SQLException, DataAccessException { + List consumersDemandNotGeneratedList=new ArrayList<>(); + while(resultSet.next()) + { + ConsumersDemandNotGenerated consumersDemandNotGenerated=new ConsumersDemandNotGenerated(); + consumersDemandNotGenerated.setConsumerCode(resultSet.getString("connectionno")); + consumersDemandNotGeneratedList.add(consumersDemandNotGenerated); + } + return consumersDemandNotGeneratedList; + } +} diff --git a/municipal-services/ws-services/src/main/java/org/egov/waterconnection/service/WaterService.java b/municipal-services/ws-services/src/main/java/org/egov/waterconnection/service/WaterService.java index 0c72cd1f8..e4c9ed73b 100644 --- a/municipal-services/ws-services/src/main/java/org/egov/waterconnection/service/WaterService.java +++ b/municipal-services/ws-services/src/main/java/org/egov/waterconnection/service/WaterService.java @@ -53,4 +53,5 @@ List collectionReport(String paymentStartDate, String paym List inactiveConsumerReport(String monthStartDate,String monthEndDate,String tenantId, @Valid Integer offset, @Valid Integer limit, RequestInfo requestInfo); + WaterConnectionResponse getConsumersWithDemandNotGenerated(String previousMeterReading, String tenantId,RequestInfo requestInfo); } diff --git a/municipal-services/ws-services/src/main/java/org/egov/waterconnection/service/WaterServiceImpl.java b/municipal-services/ws-services/src/main/java/org/egov/waterconnection/service/WaterServiceImpl.java index 704683d4b..ba0803984 100644 --- a/municipal-services/ws-services/src/main/java/org/egov/waterconnection/service/WaterServiceImpl.java +++ b/municipal-services/ws-services/src/main/java/org/egov/waterconnection/service/WaterServiceImpl.java @@ -842,4 +842,24 @@ public List inactiveConsumerReport(String monthStart List inactiveConsumerReport=waterDaoImpl.getInactiveConsumerReport(monthStartDateTime,mothEndDateTime,tenantId,offset,limit); return inactiveConsumerReport; } + + @Override + public WaterConnectionResponse getConsumersWithDemandNotGenerated(String previousMeterReading, String tenantId ,RequestInfo requestInfo) + { + Long previousReadingEpoch; + try { + previousReadingEpoch = Long.parseLong(previousMeterReading); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Invalid format for previousMeterReading. Expected a timestamp in milliseconds.", e); + } + + List list=waterDaoImpl.getConsumersByPreviousMeterReading(previousReadingEpoch,tenantId); + Set connectionNo=new HashSet<>(); + for(ConsumersDemandNotGenerated connection:list) + { + connectionNo.add(connection.getConsumerCode()); + } + SearchCriteria criteria=SearchCriteria.builder().connectionNoSet(connectionNo).tenantId(tenantId).build(); + return search(criteria,requestInfo); + } } \ No newline at end of file diff --git a/municipal-services/ws-services/src/main/java/org/egov/waterconnection/validator/WaterConnectionValidator.java b/municipal-services/ws-services/src/main/java/org/egov/waterconnection/validator/WaterConnectionValidator.java index 904661638..35ba1237a 100644 --- a/municipal-services/ws-services/src/main/java/org/egov/waterconnection/validator/WaterConnectionValidator.java +++ b/municipal-services/ws-services/src/main/java/org/egov/waterconnection/validator/WaterConnectionValidator.java @@ -20,6 +20,7 @@ import org.egov.waterconnection.service.MeterInfoValidator; import org.egov.waterconnection.service.PropertyValidator; import org.egov.waterconnection.service.WaterFieldValidator; +import org.egov.waterconnection.util.WaterServicesUtil; import org.egov.waterconnection.web.models.Demand; import org.egov.waterconnection.web.models.DemandDetail; import org.egov.waterconnection.web.models.DemandRequest; @@ -29,6 +30,7 @@ import org.egov.waterconnection.web.models.WaterConnection; import org.egov.waterconnection.web.models.WaterConnectionRequest; import org.egov.waterconnection.web.models.Connection.StatusEnum; +import org.egov.waterconnection.web.models.collection.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; @@ -62,6 +64,11 @@ public class WaterConnectionValidator { @Autowired private ObjectMapper mapper; + @Autowired + private WaterServicesUtil waterServiceUtil; + + String businessService = "WS.ONE_TIME_FEE"; + /**Used strategy pattern for avoiding multiple if else condition * * @param waterConnectionRequest @@ -176,29 +183,70 @@ public void validateUpdate(WaterConnectionRequest request, WaterConnection searc } Boolean isArrear = false; Boolean isAdvance = false; - + Boolean hasPayments=false; + + if(!request.getWaterConnection().getStatus().equals(StatusEnum.INACTIVE)) { + hasPayments = checkForPayments(request); + } + if(request.getWaterConnection().getAdvance()!=null && request.getWaterConnection().getAdvance().compareTo(BigDecimal.ZERO) == 0) { isAdvance = true; } if(request.getWaterConnection().getArrears()!=null && request.getWaterConnection().getArrears().compareTo(BigDecimal.ZERO) == 0) { isArrear = true; } - if ((request.getWaterConnection().getStatus().equals(StatusEnum.INACTIVE) && demList != null && demList.size() > 0) + if (!hasPayments && ((request.getWaterConnection().getStatus().equals(StatusEnum.INACTIVE) && demList != null && demList.size() > 0) || (searchResult.getArrears() != null && request.getWaterConnection().getArrears() == null && demList != null && demList.size() > 0 || (isArrear && demList != null && demList.size() > 0))|| (request.getWaterConnection().getStatus().equals(StatusEnum.INACTIVE) && demList != null && demList.size() > 0) || (searchResult.getAdvance() != null && request.getWaterConnection().getAdvance() == null && demList != null && demList.size() > 0 - || isAdvance)) { + || isAdvance))) { for (Demand demand : demList) { demand.setStatus(org.egov.waterconnection.web.models.Demand.StatusEnum.CANCELLED); } updateDemand(request.getRequestInfo(), demList); - + } } - - } -/** + + private Boolean checkForPayments(WaterConnectionRequest waterConnectionRequest) { + String consumerCode,service; + if(StringUtils.isEmpty(waterConnectionRequest.getWaterConnection().getConnectionNo())){ + consumerCode = waterConnectionRequest.getWaterConnection().getApplicationNo(); + service = businessService; + } + else{ + consumerCode = waterConnectionRequest.getWaterConnection().getConnectionNo(); + service = "WS"; + } + StringBuilder uri = new StringBuilder(); + uri.append(waterServiceUtil.getcollectionURL()).append(service).append("/_search").append("?"). + append("tenantId=").append(waterConnectionRequest.getWaterConnection().getTenantId()) + .append("&"). + append("consumerCodes=").append(consumerCode) + .append("&"). + append("businessService").append(service); + RequestInfoWrapper requestInfoWrapper = RequestInfoWrapper.builder().requestInfo(waterConnectionRequest.getRequestInfo()).build(); + Object response = serviceRequestRepository.fetchResult(uri,requestInfoWrapper); + PaymentResponse paymentResponse=null; + try { + paymentResponse = mapper.convertValue(response, PaymentResponse.class); + } + catch (Exception ex) + { + log.error("Response not found"); + } + if(paymentResponse.getPayments()!=null) + { + if(!paymentResponse.getPayments().isEmpty()) + { + return true; + } + } + return false; + } + + /** * GPWSC specific validation * @param request * @param searchResult diff --git a/municipal-services/ws-services/src/main/java/org/egov/waterconnection/web/controller/WaterController.java b/municipal-services/ws-services/src/main/java/org/egov/waterconnection/web/controller/WaterController.java index cd462ba50..f4da10f1f 100644 --- a/municipal-services/ws-services/src/main/java/org/egov/waterconnection/web/controller/WaterController.java +++ b/municipal-services/ws-services/src/main/java/org/egov/waterconnection/web/controller/WaterController.java @@ -235,4 +235,13 @@ public ResponseEntity countWCbyDe return new ResponseEntity<>(response, HttpStatus.OK); } + @PostMapping("/consumers/demand-not-generated") + public ResponseEntity getConsumersWithDemandNotGenerated(@Valid @RequestBody RequestInfoWrapper requestInfoWrapper,@RequestParam(value="previousMeterReading") String previousMeterReading,@RequestParam (value="tenantId") String tenantId) + { + WaterConnectionResponse response= waterService.getConsumersWithDemandNotGenerated(previousMeterReading,tenantId,requestInfoWrapper.getRequestInfo()); + response.setResponseInfo( + responseInfoFactory.createResponseInfoFromRequestInfo(requestInfoWrapper.getRequestInfo(), true)); + return new ResponseEntity<>(response, HttpStatus.OK); + } + } diff --git a/municipal-services/ws-services/src/main/java/org/egov/waterconnection/web/models/ConsumersDemandNotGenerated.java b/municipal-services/ws-services/src/main/java/org/egov/waterconnection/web/models/ConsumersDemandNotGenerated.java new file mode 100644 index 000000000..95c8e8e0b --- /dev/null +++ b/municipal-services/ws-services/src/main/java/org/egov/waterconnection/web/models/ConsumersDemandNotGenerated.java @@ -0,0 +1,13 @@ +package org.egov.waterconnection.web.models; + + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@AllArgsConstructor +@NoArgsConstructor +@Data +public class ConsumersDemandNotGenerated { + private String consumerCode; +} diff --git a/municipal-services/ws-services/src/main/java/org/egov/waterconnection/web/models/SearchCriteria.java b/municipal-services/ws-services/src/main/java/org/egov/waterconnection/web/models/SearchCriteria.java index 9c3993141..69411e1af 100644 --- a/municipal-services/ws-services/src/main/java/org/egov/waterconnection/web/models/SearchCriteria.java +++ b/municipal-services/ws-services/src/main/java/org/egov/waterconnection/web/models/SearchCriteria.java @@ -32,6 +32,9 @@ public class SearchCriteria { private Set userIds; + @JsonProperty("isOpenPaymentSearch") + private Boolean isOpenPaymentSearch; + @JsonProperty("status") private String status; diff --git a/municipal-services/ws-services/src/main/resources/application.properties b/municipal-services/ws-services/src/main/resources/application.properties index 9af349837..15949ae21 100644 --- a/municipal-services/ws-services/src/main/resources/application.properties +++ b/municipal-services/ws-services/src/main/resources/application.properties @@ -154,7 +154,7 @@ ws.pdfservice.link=pdf-service/v1/_create?tenantId=$tenantId&key=$applicationkey egov.filestore.host=http://egov-filestore:8080/ ws.fileStore.link=filestore/v1/files/url?tenantId=$tenantId&fileStoreIds=$fileStoreIds egov.shortener.url=egov-url-shortening/shortener -egov.collection.host=http://collection-services.egov:8080/ +egov.collection.host=http://collection-services.mgramseva:8080/ logging.level.org.egov.waterconnection=DEBUG @@ -202,3 +202,7 @@ sms.edit.water.connection.notification.enabled: true sms.payment.notification.enabled: true sms.feedback.notification.enabled: false sms.workflow.enabled: true + +#ES-config +egov.indexer.es.username=elastic +egov.indexer.es.password=8fwbD6HbJh6HU0oddsHm8TEI diff --git a/utilities/rollout-dashboard-cronjob-indexer/.env b/utilities/rollout-dashboard-cronjob-indexer/.env new file mode 100644 index 000000000..fd557a7c8 --- /dev/null +++ b/utilities/rollout-dashboard-cronjob-indexer/.env @@ -0,0 +1,11 @@ +# Database Credentials +DB_HOST=test +DB_SCHEMA=test +DB_USER=test +DB_PWD=tesrt +DB_PORT=5432 + +#mdms call +API_URL= https://localhost:8080/ +TENANT_ID=pb +IFIX_DEP_ENTITY_URL= https://localhost:8080/ diff --git a/utilities/rollout-dashboard-cronjob-indexer/CHANGELOG.md b/utilities/rollout-dashboard-cronjob-indexer/CHANGELOG.md new file mode 100644 index 000000000..f6d8a5c21 --- /dev/null +++ b/utilities/rollout-dashboard-cronjob-indexer/CHANGELOG.md @@ -0,0 +1,7 @@ +# Changelog + +All notable changes to this module will be documented in this file. + + +## 1.0.0 - 2024-07-02 +Rollouot Dashboard indexer initial version release diff --git a/utilities/rollout-dashboard-cronjob-indexer/Dockerfile b/utilities/rollout-dashboard-cronjob-indexer/Dockerfile new file mode 100644 index 000000000..769eb225d --- /dev/null +++ b/utilities/rollout-dashboard-cronjob-indexer/Dockerfile @@ -0,0 +1,17 @@ +FROM python:3.9-slim-buster + +RUN apt-get update && apt-get install -y \ + build-essential \ + libpq-dev \ + && rm -rf /var/lib/apt/lists/* +WORKDIR /app/cron/ +COPY requirements.txt . + +RUN python3.9 -m pip install --no-cache-dir --upgrade \ + pip \ + setuptools \ + wheel +RUN python3.9 -m pip install --no-cache-dir \ + -r requirements.txt + +COPY app.py app.py \ No newline at end of file diff --git a/utilities/rollout-dashboard-cronjob-indexer/LOCALSETUP.md b/utilities/rollout-dashboard-cronjob-indexer/LOCALSETUP.md new file mode 100644 index 000000000..57fbca353 --- /dev/null +++ b/utilities/rollout-dashboard-cronjob-indexer/LOCALSETUP.md @@ -0,0 +1,15 @@ +For local setup: + 1. install python version3. + refer link for installing python 3 on linux system--> https://computingforgeeks.com/how-to-install-python-on-ubuntu-linux-system/ + 2. install pip3 + ex. apt install python3-pip + for version check -> pip3 --version + refer link: https://digit-discuss.atlassian.net/wiki/spaces/DD/pages/1865777171/DIGIT+Internal+Datamart+deployment+steps + 3. install required libraries like requests, pandas, psycopg2-binary etc. mentiond in requirnments.txt file using pip command. + ex. pip3 install requests + 4. To run the application locally, we have to load the variable from the .env file to environment so that script can use to do so run below command (NOTE: this to run locally, when running on the pod these variables will be loaded from help) + ``while read LINE; do export "$LINE"; done < ./.env`` + 4. for running app.py use command + ex. python3 app.py + + diff --git a/utilities/rollout-dashboard-cronjob-indexer/README.md b/utilities/rollout-dashboard-cronjob-indexer/README.md new file mode 100644 index 000000000..6f79e9cf8 --- /dev/null +++ b/utilities/rollout-dashboard-cronjob-indexer/README.md @@ -0,0 +1,2 @@ +1. Written python script collecting for each tenant data from mdms and mgramseva db based on some critria commented in script 'app.py' for each method. +2. Collecting data and dumping data into mgramseva db in 'roll_out_dashboard' table then loading that data into metabase. diff --git a/utilities/rollout-dashboard-cronjob-indexer/app.py b/utilities/rollout-dashboard-cronjob-indexer/app.py new file mode 100644 index 000000000..f419773de --- /dev/null +++ b/utilities/rollout-dashboard-cronjob-indexer/app.py @@ -0,0 +1,1074 @@ +import json +from typing import BinaryIO, List +import requests +from datetime import datetime, timezone, time, timedelta, date +from dateutil.relativedelta import relativedelta +from dateutil import tz +import pytz +from dateutil import parser +from decimal import Decimal +import os +import psycopg2 + + +def getGPWSCHeirarchy(): + # call the projectmodule mdms for each unique tenant which would return the array of unique villages( i.e tenantid) along with the respectie + # zone circle division subdivision project + # https://realpython.com/python-requests/ helps on how make ajax calls. url put it in app.properties and read through configs + + try: + mdms_url = os.getenv('API_URL') + state_tenantid = os.getenv('TENANT_ID') + mdms_requestData = { + "RequestInfo": { + "apiId": "mgramseva-common", + "ver": 0.01, + "ts": "", + "action": "_search", + "did": 1, + "key": "", + "msgId": "" + }, + "MdmsCriteria": { + "tenantId": state_tenantid, + "moduleDetails": [ + { + "moduleName": "tenant", + "masterDetails": [ + { + "name": "tenants" + } + ] + } + ] + } + } + + mdms_response = requests.post(mdms_url + 'mdms-v2/v1/_search', json=mdms_requestData, verify=False) + + mdms_responseData = mdms_response.json() + tenantList = mdms_responseData['MdmsRes']['tenant']['tenants'] + print(len(tenantList)) + teanant_data_Map = {} + for tenant in tenantList: + if tenant.get('code') == state_tenantid or tenant.get('code') == (state_tenantid + '.testing'): + continue + if tenant.get('city') is not None and tenant.get('city').get('code') is not None: + teanant_data_Map.update({tenant.get('city').get('code'): tenant.get('code')}) + + url = 'https://mgramseva-dwss.punjab.gov.in/' + print(url) + requestData = { + "requestHeader": { + "ts": 1627193067, + "version": "2.0.0", + "msgId": "Unknown", + "signature": "NON", + "userInfo": { + "uuid": "admin" + } + }, + "criteria": { + "tenantId": "pb", + "getAncestry": True + } + } + + response = requests.post(url + 'ifix-department-entity/departmentEntity/v1/_search', json=requestData, + verify=False) + + responseData = response.json() + departmentHierarchyList = responseData.get('departmentEntity') + dataList = [] + + for data in departmentHierarchyList: + if (len(data['children']) > 0): + if (data.get('hierarchyLevel') == 0): + child = data['children'][0] + else: + child = data + zone = child.get('name') + if (len(child['children']) > 0): + circle = child['children'][0].get('name') + if (len(child['children'][0]['children']) > 0): + division = child['children'][0]['children'][0].get('name') + if (len(child['children'][0]['children'][0]['children']) > 0): + subdivision = child['children'][0]['children'][0]['children'][0].get('name') + if (len(child['children'][0]['children'][0]['children'][0]['children']) > 0): + section = child['children'][0]['children'][0]['children'][0]['children'][0].get('name') + if (len(child['children'][0]['children'][0]['children'][0]['children'][0][ + 'children']) > 0): + tenantName = \ + child['children'][0]['children'][0]['children'][0]['children'][0]['children'][ + 0].get( + 'name') + tenantCode = \ + child['children'][0]['children'][0]['children'][0]['children'][0]['children'][ + 0].get( + 'code') + # tenantId = tenantName.replace(" ", "").lower() + if teanant_data_Map.get(tenantCode) is not None: + formatedTenantId = teanant_data_Map.get(tenantCode) + #tenantName=teanant_data_Map.get(tenantCode)['name'] + print(teanant_data_Map) + # print(formatedTenantId) + obj1 = {"tenantId": formatedTenantId, "zone": zone, "circle": circle, + "division": division, "subdivision": subdivision, + "section": section, "projectcode": tenantCode,"tenantName":tenantName} + dataList.append(obj1) + print("heirarchy collected") + # print(dataList) + return (dataList) + except Exception as exception: + print("Exception occurred while connecting to the database") + print(exception) + + +def getRateMasters(tenantId): + # make mdms call to get the rate unique rate masters i.e billig slab . count the unique billing slabs and return the number + print("Rate master count returned") + try: + + url = os.getenv('API_URL') + + requestData = { + "RequestInfo": { + "apiId": "mgramseva-common", + "ver": 0.01, + "ts": "", + "action": "_search", + "did": 1, + "key": "", + "msgId": "" + }, + "MdmsCriteria": { + "tenantId": tenantId, + "moduleDetails": [ + { + "moduleName": "ws-services-calculation", + "masterDetails": [ + { + "name": "WCBillingSlab" + } + ] + } + ] + } + } + + response = requests.post(url + 'mdms-v2/v1/_search', json=requestData) + + responseData = response.json() + wcBillingSlabList = responseData['MdmsRes']['ws-services-calculation']['WCBillingSlab'] + + return len(wcBillingSlabList) + except Exception as exception: + print("Exception occurred while connecting to the database") + print(exception) + + +def getCollectionsMade(tenantId, startdate, enddate): + # make db call with query to get the collections made in the current date in the given tenant + # should be till date not current date. + print("collections made returned") + try: + connection = getConnection() + cursor = connection.cursor() + + if startdate != None and enddate != None: + COLLECTION_MADE_TILL_THE_CURRENT_DATE_QUERY = "select sum(amountpaid) from egcl_paymentdetail where businessservice = 'WS' and createdtime between '" + startdate + "'" + " and '" + enddate + "'" + " and tenantid = '" + tenantId + "'" + else: + COLLECTION_MADE_TILL_THE_CURRENT_DATE_QUERY = "select sum(amountpaid) from egcl_paymentdetail where businessservice = 'WS' and tenantid = '" + tenantId + "'" + + cursor.execute(COLLECTION_MADE_TILL_THE_CURRENT_DATE_QUERY) + result = cursor.fetchone() + print(result[0]) + return result[0] + + except Exception as exception: + print("Exception occurred while connecting to the database") + print(exception) + + finally: + if connection: + cursor.close() + connection.close() + + +def getCollectionsMadeOnline(tenantId): + # make db call with query to get the collections made in the current date of type online in the given tenant, as of now no data exists but write the query + # should be till date not current date. + + print("collections made online returned") + try: + connection = getConnection() + cursor = connection.cursor() + + COLLECTION_MADE_TILL_THE_CURRENT_DATE_ONLINE_QUERY = "select sum(pd.amountpaid) from egcl_payment p join egcl_paymentdetail pd on p.id = pd.paymentid where pd.businessservice = 'WS' and p.tenantid = '" + tenantId + "'" + " and p.paymentmode = 'ONLINE' " + + cursor.execute(COLLECTION_MADE_TILL_THE_CURRENT_DATE_ONLINE_QUERY) + result = cursor.fetchone() + print(result[0]) + return result[0] + + except Exception as exception: + print("Exception occurred while connecting to the database") + print(exception) + + finally: + if connection: + cursor.close() + connection.close() + + +def getLastCollectionDate(tenantId, startdate, enddate): + # make db call to get the last collection date for the given tenant + print("lat collection date returned") + try: + connection = getConnection() + cursor = connection.cursor() + if startdate != None and enddate != None: + LAST_COLLECTION_DATE_QUERY = "select createdtime from egcl_paymentdetail where businessservice = 'WS' and createdtime between '" + startdate + "'" + " and '" + enddate + "'" + " and tenantid = '" + tenantId + "'" + " order by createdtime desc limit 1" + else: + LAST_COLLECTION_DATE_QUERY = "select createdtime from egcl_paymentdetail where businessservice = 'WS' and tenantid = '" + tenantId + "'" + " order by createdtime desc limit 1" + + cursor.execute(LAST_COLLECTION_DATE_QUERY) + result = cursor.fetchone() + + formatedDate = datetime.fromtimestamp(result[0] / 1000.0) + + print(formatedDate) + return formatedDate + except Exception as exception: + print("Exception occurred while connecting to the database") + print(exception) + + finally: + if connection: + cursor.close() + connection.close() + + +def getExpenseBillEntered(tenantId, startdate, enddate): + # make db call to get the total no of expenses entered in the give tenant on the current date + # total till date not current date + + print("expense bill entered returned") + try: + connection = getConnection() + cursor = connection.cursor() + if startdate != None and enddate != None: + TOTAL_NO_EXPENSES_TILL_DATE = "select count(*) from eg_echallan where typeofexpense<>'ELECTRICITY_BILL' and applicationstatus='ACTIVE' and createdtime between '" + startdate + "'" + " and '" + enddate + "'" + " and tenantid = '" + tenantId + "'" + else: + TOTAL_NO_EXPENSES_TILL_DATE = "select count(*) from eg_echallan where typeofexpense<>'ELECTRICITY_BILL' and applicationstatus='ACTIVE' and tenantid = '" + tenantId + "'" + + cursor.execute(TOTAL_NO_EXPENSES_TILL_DATE) + result = cursor.fetchone() + print(result[0]) + return result[0] + + except Exception as exception: + print("Exception occurred while connecting to the database") + print(exception) + + finally: + if connection: + cursor.close() + connection.close() + + +def getElectricityExpenseBillEntered(tenantId, startdate, enddate): + # make db call to get the total no of expenses entered in the give tenant on the current date + # total till date not current date + + print("expense bill entered returned") + try: + connection = getConnection() + cursor = connection.cursor() + if startdate != None and enddate != None: + TOTAL_NO_EXPENSES_TILL_DATE = "select count(*) from eg_echallan where typeofexpense='ELECTRICITY_BILL' and applicationstatus='ACTIVE' and createdtime between '" + startdate + "'" + " and '" + enddate + "'" + " and tenantid = '" + tenantId + "'" + else: + TOTAL_NO_EXPENSES_TILL_DATE = "select count(*) from eg_echallan where typeofexpense='ELECTRICITY_BILL' and applicationstatus='ACTIVE' and tenantid = '" + tenantId + "'" + + cursor.execute(TOTAL_NO_EXPENSES_TILL_DATE) + result = cursor.fetchone() + print(result[0]) + return result[0] + + except Exception as exception: + print("Exception occurred while connecting to the database") + print(exception) + + finally: + if connection: + cursor.close() + connection.close() + + +def getLastExpTransactionDate(tenantId, startdate, enddate): + # make db call to get the latest expense bill entered date in that given tenant + print("expense transaction date") + try: + connection = getConnection() + cursor = connection.cursor() + if startdate != None and enddate != None: + LAT_EXP_BILL_DATE = "select createdtime from eg_echallan where applicationstatus='ACTIVE' and createdtime between '" + startdate + "'" + " and '" + enddate + "'" + " and tenantid = '" + tenantId + "'" + " order by createdtime desc limit 1" + else: + LAT_EXP_BILL_DATE = "select createdtime from eg_echallan where applicationstatus='ACTIVE' and tenantid = '" + tenantId + "'" + " order by createdtime desc limit 1" + + cursor.execute(LAT_EXP_BILL_DATE) + result = cursor.fetchone() + formatedDate = datetime.fromtimestamp(result[0] / 1000.0) + print(formatedDate) + return formatedDate + + except Exception as exception: + print("Exception occurred while connecting to the database") + print(exception) + + finally: + if connection: + cursor.close() + connection.close() + + +def getNoOfBillsPaid(tenantId, startdate, enddate): + # make db call to get total no of expenses bills marked as paid till current date. + print("No of bill paid") + try: + connection = getConnection() + cursor = connection.cursor() + if startdate != None and enddate != None: + TOTAL_EXPENSES_BILL_MARKED_PAID = "select count(*) from eg_echallan where typeofexpense<>'ELECTRICITY_BILL' and applicationstatus = 'PAID' and createdtime between '" + startdate + "'" + " and '" + enddate + "'" + " and tenantid = '" + tenantId + "'" + else: + TOTAL_EXPENSES_BILL_MARKED_PAID = "select count(*) from eg_echallan where typeofexpense<>'ELECTRICITY_BILL' and tenantid = '" + tenantId + "'" + " and applicationstatus = 'PAID' " + + cursor.execute(TOTAL_EXPENSES_BILL_MARKED_PAID) + result = cursor.fetchone() + print(result[0]) + return result[0] + except Exception as exception: + print("Exception occurred while connecting to the database") + print(exception) + + finally: + if connection: + cursor.close() + connection.close() + + +def getTotalAmountExpenseBills(tenantId, startdate, enddate): + # make db call to get total no of expenses bills marked as paid till current date. + print("No of bill paid") + try: + connection = getConnection() + cursor = connection.cursor() + if startdate != None and enddate != None: + TOTAL_EXPENSES_BILL_MARKED_PAID = "select sum(dd.taxamount) from eg_echallan challan inner join egbs_Demand_v1 dem on dem.consumercode=challan.referenceid inner join egbs_Demanddetail_v1 dd on dem.id=dd.demandid where dem.status='ACTIVE' and challan.typeofexpense<>'ELECTRICITY_BILL' and challan.createdtime between '" + startdate + "'" + " and '" + enddate + "'" + " and dem.tenantid = '" + tenantId + "'" + else: + TOTAL_EXPENSES_BILL_MARKED_PAID = "select sum(dd.taxamount) from eg_echallan challan inner join egbs_Demand_v1 dem on dem.consumercode=challan.referenceid inner join egbs_Demanddetail_v1 dd on dem.id=dd.demandid where dem.status='ACTIVE' and challan.typeofexpense<>'ELECTRICITY_BILL' and dem.tenantid = '" + tenantId + "'" + + cursor.execute(TOTAL_EXPENSES_BILL_MARKED_PAID) + result = cursor.fetchone() + print(result[0]) + return result[0] + except Exception as exception: + print("Exception occurred while connecting to the database") + print(exception) + + finally: + if connection: + cursor.close() + connection.close() + + +def getTotalAmountElectricityBills(tenantId, startdate, enddate): + # make db call to get total no of expenses bills marked as paid till current date. + print("No of bill paid") + try: + connection = getConnection() + cursor = connection.cursor() + if startdate != None and enddate != None: + TOTAL_EXPENSES_BILL_MARKED_PAID = "select sum(dd.taxamount) from eg_echallan challan inner join egbs_Demand_v1 dem on dem.consumercode=challan.referenceid inner join egbs_Demanddetail_v1 dd on dem.id=dd.demandid where dem.status='ACTIVE' and challan.typeofexpense='ELECTRICITY_BILL' and challan.createdtime between '" + startdate + "'" + " and '" + enddate + "'" + " and dem.tenantid = '" + tenantId + "'" + else: + TOTAL_EXPENSES_BILL_MARKED_PAID = "select sum(dd.taxamount) from eg_echallan challan inner join egbs_Demand_v1 dem on dem.consumercode=challan.referenceid inner join egbs_Demanddetail_v1 dd on dem.id=dd.demandid where dem.status='ACTIVE' and challan.typeofexpense='ELECTRICITY_BILL' and dem.tenantid = '" + tenantId + "'" + + cursor.execute(TOTAL_EXPENSES_BILL_MARKED_PAID) + result = cursor.fetchone() + print(result[0]) + return result[0] + except Exception as exception: + print("Exception occurred while connecting to the database") + print(exception) + + finally: + if connection: + cursor.close() + connection.close() + + +def getTotalAmountPaidBills(tenantId, startdate, enddate): + # make db call to get total no of expenses bills marked as paid till current date. + print("No of bill paid") + try: + connection = getConnection() + cursor = connection.cursor() + if startdate != None and enddate != None: + TOTAL_EXPENSES_BILL_MARKED_PAID = "select sum(dd.taxamount) from eg_echallan challan inner join egbs_Demand_v1 dem on dem.consumercode=challan.referenceid inner join egbs_Demanddetail_v1 dd on dem.id=dd.demandid where challan.applicationstatus='PAID' and challan.typeofexpense<>'ELECTRICITY_BILL' and challan.createdtime between '" + startdate + "'" + " and '" + enddate + "'" + " and dem.tenantid = '" + tenantId + "'" + else: + TOTAL_EXPENSES_BILL_MARKED_PAID = "select sum(dd.taxamount) from eg_echallan challan inner join egbs_Demand_v1 dem on dem.consumercode=challan.referenceid inner join egbs_Demanddetail_v1 dd on dem.id=dd.demandid where challan.applicationstatus='PAID' and challan.typeofexpense<>'ELECTRICITY_BILL' and dem.tenantid = '" + tenantId + "'" + + cursor.execute(TOTAL_EXPENSES_BILL_MARKED_PAID) + result = cursor.fetchone() + print(result[0]) + return result[0] + except Exception as exception: + print("Exception occurred while connecting to the database") + print(exception) + + finally: + if connection: + cursor.close() + connection.close() + + +def getRatingCount(tenantId): + # make db call to get the total no of ratings + print("no of ratings") + try: + connection = getConnection() + cursor = connection.cursor() + + TOTAL_RATINGS = "select count(*) from eg_ws_feedback where tenantid = '" + tenantId + "'" + + cursor.execute(TOTAL_RATINGS) + result = cursor.fetchone() + print(result[0]) + return result[0] + + except Exception as exception: + print("Exception occurred while connecting to the database") + print(exception) + + finally: + if connection: + cursor.close() + connection.close() + + +def getLastRatingDate(tenantId): + # make db call to get the last rating date entered date in that given tenant + print("last rating date geiven") + try: + connection = getConnection() + cursor = connection.cursor() + LAST_RATING_DATE = "select createdtime from eg_ws_feedback where tenantid = '" + tenantId + "'" + " order by createdtime desc limit 1" + + cursor.execute(LAST_RATING_DATE) + result = cursor.fetchone() + formatedDate = datetime.fromtimestamp(result[0] / 1000.0) + print(formatedDate) + return formatedDate + + except Exception as exception: + print("Exception occurred while connecting to the database") + print(exception) + + finally: + if connection: + cursor.close() + connection.close() + + +def getActiveUsersCount(tenantId): + # make db call to get the total no of active users(EMPLOYEE) + print("no of active users") + try: + connection = getConnection() + cursor = connection.cursor() + + NO_OF_ACTIVE_USERS = "select count(distinct ur.user_id) from eg_user u inner join eg_userrole_v1 ur on u.id = ur.user_id where u.active = 't' and u.type='EMPLOYEE' and ur.role_tenantid = '" + tenantId + "'" + + cursor.execute(NO_OF_ACTIVE_USERS) + result = cursor.fetchone() + print(result[0]) + return result[0] + + except Exception as exception: + print("Exception occurred while connecting to the database") + print(exception) + + finally: + if connection: + cursor.close() + connection.close() + + +def getTotalAdvanceCreated(tenantId, startdate, enddate): + # query the postgresql db to get the total count of total advance in the given tenant till date + print("advance sum returned") + try: + connection = getConnection() + cursor = connection.cursor() + + if startdate != None and enddate != None: + ADVANCE_COUNT_QUERY = "select sum(dd.taxamount) from egbs_demanddetail_v1 dd inner join egbs_demand_v1 d on dd.demandid = d.id where d.status = 'ACTIVE' and dd.taxheadcode='WS_ADVANCE_CARRYFORWARD' and d.createdtime between '" + startdate + "'" + " and '" + enddate + "'" + " and d.tenantid = '" + tenantId + "'" + else: + ADVANCE_COUNT_QUERY = "select sum(dd.taxamount) from egbs_demanddetail_v1 dd inner join egbs_demand_v1 d on dd.demandid = d.id where d.status = 'ACTIVE' and dd.taxheadcode='WS_ADVANCE_CARRYFORWARD' and d.tenantid = '" + tenantId + "'" + + cursor.execute(ADVANCE_COUNT_QUERY) + result = cursor.fetchone() + print(result[0]) + return result[0] + + except Exception as exception: + print("Exception occurred while connecting to the database") + print(exception) + + finally: + if connection: + cursor.close() + connection.close() + + +def getTotalPenaltyCreated(tenantId, startdate, enddate): + # query the postgresql db to get the total count of total penalty in the given tenant till date + print("penalty sum returned") + try: + connection = getConnection() + cursor = connection.cursor() + + if startdate != None and enddate != None: + PENALTY_COUNT_QUERY = "select sum(dd.taxamount) from egbs_demanddetail_v1 dd inner join egbs_demand_v1 d on dd.demandid = d.id where d.status = 'ACTIVE' and dd.taxheadcode='WS_TIME_PENALTY' and d.createdtime between '" + startdate + "'" + " and '" + enddate + "'" + " and d.tenantid = '" + tenantId + "'" + else: + PENALTY_COUNT_QUERY = "select sum(dd.taxamount) from egbs_demanddetail_v1 dd inner join egbs_demand_v1 d on dd.demandid = d.id where d.status = 'ACTIVE' and dd.taxheadcode='WS_TIME_PENALTY' and d.tenantid = '" + tenantId + "'" + + cursor.execute(PENALTY_COUNT_QUERY) + result = cursor.fetchone() + print(result[0]) + return result[0] + + except Exception as exception: + print("Exception occurred while connecting to the database") + print(exception) + + finally: + if connection: + cursor.close() + connection.close() + + +def getConsumersCount(tenantId, startdate, enddate): + print("consumer count returned") + try: + connection = getConnection() + cursor = connection.cursor() + + if startdate != None and enddate != None: + CONSUMER_COUNT = "select count(*) from eg_ws_connection where status = 'Active' and createdtime between '" + startdate + "'" + " and '" + enddate + "'" + " and tenantid = '" + tenantId + "'" + else: + CONSUMER_COUNT = "select count(*) from eg_ws_connection where status = 'Active' and tenantid = '" + tenantId + "'" + cursor.execute(CONSUMER_COUNT) + result = cursor.fetchone() + print(result[0]) + return result[0] + + except Exception as exception: + print("Exception occurred while connecting to the database") + print(exception) + + finally: + if connection: + cursor.close() + connection.close() + + +def getTotalConsumerCount(tenantId, startdate, enddate): + print("consumer count returned") + try: + connection = getConnection() + cursor = connection.cursor() + + if startdate != None and enddate != None: + CONSUMER_COUNT = "select count(*) from eg_ws_connection where createdtime between '" + startdate + "'" + " and '" + enddate + "'" + " and tenantid = '" + tenantId + "'" + else: + CONSUMER_COUNT = "select count(*) from eg_ws_connection where tenantid = '" + tenantId + "'" + cursor.execute(CONSUMER_COUNT) + result = cursor.fetchone() + print(result[0]) + return result[0] + + except Exception as exception: + print("Exception occurred while connecting to the database") + print(exception) + + finally: + if connection: + cursor.close() + connection.close() + + +def getLastDemandDate(tenantId, startdate, enddate): + print("last demand date returned") + try: + connection = getConnection() + cursor = connection.cursor() + + if startdate != None and enddate != None: + LAST_DEMAND_DATE = "select max(to_timestamp(taxperiodto/1000)::date) from eg_ws_connection conn left outer join egbs_demand_v1 dmd on dmd.consumercode=conn.connectionno and dmd.status='ACTIVE' left outer join egbs_demanddetail_v1 dtl on dtl.demandid=dmd.id and taxheadcode='10101' where dtl.id is not null and conn.status='Active'and businessservice='WS' and (EXTRACT(epoch FROM (to_timestamp(taxperiodto/1000))-to_timestamp(taxperiodfrom/1000)))::int/86400<=31 and dmd.createdtime between '" + startdate + "'" + " and '" + enddate + "'" + " and dmd.tenantid = '" + tenantId + "'" + else: + LAST_DEMAND_DATE = "select max(to_timestamp(taxperiodto/1000)::date) from eg_ws_connection conn left outer join egbs_demand_v1 dmd on dmd.consumercode=conn.connectionno and dmd.status='ACTIVE' left outer join egbs_demanddetail_v1 dtl on dtl.demandid=dmd.id and taxheadcode='10101' where dtl.id is not null and conn.status='Active'and businessservice='WS' and (EXTRACT(epoch FROM (to_timestamp(taxperiodto/1000))-to_timestamp(taxperiodfrom/1000)))::int/86400<=31 and dmd.tenantid = '" + tenantId + "'" + + cursor.execute(LAST_DEMAND_DATE) + result = cursor.fetchone() + + return result[0] + + except Exception as exception: + print("Exception occurred while connecting to the database") + print(exception) + + finally: + if connection: + cursor.close() + connection.close() + + +def getTotalDemandRaised(tenantId, startdate, enddate): + print("last demand date returned") + try: + connection = getConnection() + cursor = connection.cursor() + if startdate != None and enddate != None: + LAST_DEMAND_COUNT = "select count(distinct dmd.consumercode) from eg_ws_connection conn left outer join egbs_demand_v1 dmd on dmd.consumercode=conn.connectionno and dmd.status='ACTIVE' left outer join egbs_demanddetail_v1 dtl on dtl.demandid=dmd.id and taxheadcode='10101' where conn.status='Active'and businessservice='WS' and dtl.id is not null and (EXTRACT(epoch FROM (to_timestamp(taxperiodto/1000))-to_timestamp(taxperiodfrom/1000)))::int/86400<=31 and dmd.createdtime between '" + startdate + "'" + " and '" + enddate + "'" + " and dmd.tenantid = '" + tenantId + "' group by taxperiodto order by taxperiodto desc limit 1 " + else: + LAST_DEMAND_COUNT = "select count(distinct dmd.consumercode) from eg_ws_connection conn left outer join egbs_demand_v1 dmd on dmd.consumercode=conn.connectionno and dmd.status='ACTIVE' left outer join egbs_demanddetail_v1 dtl on dtl.demandid=dmd.id and taxheadcode='10101' where conn.status='Active'and businessservice='WS' and dtl.id is not null and (EXTRACT(epoch FROM (to_timestamp(taxperiodto/1000))-to_timestamp(taxperiodfrom/1000)))::int/86400<=31 and dmd.tenantid = '" + tenantId + "' group by taxperiodto order by taxperiodto desc limit 1" + + cursor.execute(LAST_DEMAND_COUNT) + result = cursor.fetchone() + + return result[0] + + except Exception as exception: + print("Exception occurred while connecting to the database") + print(exception) + + finally: + if connection: + cursor.close() + connection.close() + + +def getTotalDemandAmount(tenantId, startdate, enddate): + print("demand amount returned") + try: + connection = getConnection() + cursor = connection.cursor() + if startdate != None and enddate != None: + TOTAL_DEMAND_AMOUNT = "select sum(dd.taxamount) from egbs_demand_v1 dem inner join egbs_demanddetail_v1 dd on dem.id=dd.demandid where dem.status='ACTIVE' and dem.businessservice='WS' and dd.taxheadcode<>'WS_ADVANCE_CARRYFORWARD' and dem.createdtime between '" + startdate + "'" + " and '" + enddate + "'" + " and dem.tenantid = '" + tenantId + "'" + else: + TOTAL_DEMAND_AMOUNT = "select sum(dd.taxamount) from egbs_demand_v1 dem inner join egbs_demanddetail_v1 dd on dem.id=dd.demandid where dem.status='ACTIVE' and dem.businessservice='WS' and dd.taxheadcode<>'WS_ADVANCE_CARRYFORWARD' and dem.tenantid = '" + tenantId + "'" + + cursor.execute(TOTAL_DEMAND_AMOUNT) + result = cursor.fetchone() + + print(result[0]) + return result[0] + + except Exception as exception: + print("Exception occurred while connecting to the database") + print(exception) + + finally: + if connection: + cursor.close() + connection.close() + + +def getdaterange(i): + epochnow = None; + lastepoch = None + if i == 'Last seven days': + now = datetime.now() + lastSevenDays = (now - timedelta(days=7)).replace(hour=0, minute=0, second=0, microsecond=0) + lastepoch = now.strftime('%s') + '000' + epochnow = lastSevenDays.strftime('%s') + '000' + + if i == 'Last 15 days': + now = datetime.now() + lastFifteenDays = (now - timedelta(days=15)).replace(hour=0, minute=0, second=0, microsecond=0) + lastepoch = now.strftime('%s') + '000' + epochnow = lastFifteenDays.strftime('%s') + '000' + + if i == 'currentMonth-Till date': + today = datetime.now().year + currentMonth = datetime.now().month + start_date = datetime(today, currentMonth, 1) + epochnow = start_date.strftime('%s') + '000' + lastepoch = datetime.now().strftime('%s') + '000' + + if i == 'Previous Month': + nowdate = datetime.now() + today = nowdate.year + lastonemonth = (nowdate - relativedelta(months=1)).month + if lastonemonth == 12: + start_date = datetime(today - 1, lastonemonth, 1) + end_date = datetime(today, 1, 1) + timedelta(days=-1) + else: + start_date = datetime(today, lastonemonth, 1) + end_date = datetime(today, lastonemonth + 1, 1) + timedelta(days=-1) + enddate = end_date.combine(end_date, time.max) + epochnow = start_date.strftime('%s') + '000' + lastepoch = enddate.strftime('%s') + '000' + + if i == 'Quarter-1': + month = datetime.now().month + if (month < 4): + year = datetime.now().year - 1 + else: + year = datetime.now().year + start_date = datetime(year, 4, 1) + end_date = datetime(year, 6, 30) + end = datetime.combine(end_date, time.max) + epochnow = start_date.strftime('%s') + '000' + lastepoch = end.strftime('%s') + '000' + + if i == 'Quarter-2': + month = datetime.now().month + if (month < 4): + year = datetime.now().year - 1 + else: + year = datetime.now().year + start_date = datetime(year, 7, 1) + end_date = datetime(year, 9, 30) + end = datetime.combine(end_date, time.max) + epochnow = start_date.strftime('%s') + '000' + lastepoch = end.strftime('%s') + '000' + + if i == 'Quarter-3': + month = datetime.now().month + if (month < 4): + year = datetime.now().year - 1 + else: + year = datetime.now().year + start_date = datetime(year, 10, 1) + end_date = datetime(year, 12, 31) + end = datetime.combine(end_date, time.max) + epochnow = start_date.strftime('%s') + '000' + lastepoch = end.strftime('%s') + '000' + + if i == 'Quarter-4': + year = datetime.now().year + start_date = datetime(year, 1, 1) + end_date = datetime(year, 3, 31) + end = datetime.combine(end_date, time.max) + epochnow = start_date.strftime('%s') + '000' + lastepoch = end.strftime('%s') + '000' + + if i == 'FY to date': + today = datetime.now().year + month = datetime.now().month + if (month < 4): + start_date = datetime(today - 1, 4, 1) + else: + start_date = datetime(today, 4, 1) + epochnow = start_date.strftime('%s') + '000' + lastepoch = datetime.now().strftime('%s') + '000' + + if i == 'Previous 1st FY (23-24)': + today = datetime.now().year + lastyear = today - 1 + start_date = datetime(lastyear, 4, 1) + end_date = datetime(today, 4, 1) + timedelta(days=-1) + enddate = end_date.combine(end_date, time.max) + epochnow = start_date.strftime('%s') + '000' + lastepoch = enddate.strftime('%s') + '000' + + if i == 'Previous 2nd FY (22-23)': + today = datetime.now().year + start_date = datetime(today - 2, 4, 1) + end_date = datetime(today - 1, 4, 1) + timedelta(days=-1) + enddate = end_date.combine(end_date, time.max) + epochnow = start_date.strftime('%s') + '000' + lastepoch = enddate.strftime('%s') + '000' + + if i == 'Previous 3rd FY (21-22)': + today = datetime.now().year + start_date = datetime(today - 3, 4, 1) + end_date = datetime(today - 2, 4, 1) + timedelta(days=-1) + enddate = end_date.combine(end_date, time.max) + epochnow = start_date.strftime('%s') + '000' + lastepoch = enddate.strftime('%s') + '000' + + return epochnow, lastepoch + + +def createEntryForRollout(tenant, activeUsersCount, totalAdvance, totalPenalty, totalConsumerCount, consumerCount, + lastDemandGenratedDate, noOfDemandRaised, totaldemAmount, collectionsMade, lastCollectionDate, + expenseCount, countOfElectricityExpenseBills, noOfPaidExpenseBills, lastExpTrnsDate, + totalAmountOfExpenseBills, totalAmountOfElectricityBills, totalAmountOfPaidExpenseBills, + date): + # create entry into new table in postgres db with the table name roll_outdashboard . enter all field into the db and additional createdtime additional column + + print("inserting data into db") + try: + connection = getConnection() + cursor = connection.cursor() + + # createdTime = int(round(time.time() * 1000)) // time in currenttimemillis format + + tzInfo = pytz.timezone('Asia/Kolkata') + createdTime = datetime.now(tz=tzInfo) + print("createdtime -->", createdTime) + + postgres_insert_query = "INSERT INTO roll_out_dashboard (tenantid, projectcode, zone, circle, division, subdivision, section,active_users_count,total_advance,total_penalty,total_connections,active_connections, last_demand_gen_date, demand_generated_consumer_count,total_demand_amount,collection_till_date,last_collection_date,expense_count,count_of_electricity_expense_bills,no_of_paid_expense_bills,last_expense_txn_date,total_amount_of_expense_bills,total_amount_of_electricity_bills,total_amount_of_paid_expense_bills,date_range,createdtime) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)" + record_to_insert = ( + tenant['tenantId'], tenant['projectcode'], tenant['zone'], tenant['circle'], tenant['division'], + tenant['subdivision'], tenant['section'], activeUsersCount, totalAdvance, totalPenalty, totalConsumerCount, + consumerCount, lastDemandGenratedDate, noOfDemandRaised, totaldemAmount, collectionsMade, lastCollectionDate, + expenseCount, countOfElectricityExpenseBills, noOfPaidExpenseBills, lastExpTrnsDate, totalAmountOfExpenseBills, + totalAmountOfElectricityBills, totalAmountOfPaidExpenseBills, date, createdTime) + cursor.execute(postgres_insert_query, record_to_insert) + + connection.commit() + return + + except (Exception, psycopg2.Error) as error: + print("Exception occurred while connecting to the database") + print(exception) + + finally: + if connection: + cursor.close() + connection.close() + + +def convert_decimal_to_float(value): + return float(value) if isinstance(value, Decimal) else value + + +def convert_date_to_string(value): + return value.isoformat() if isinstance(value, (date, datetime)) else None + + +def createEntryForRolloutToElasticSearch(tenant, activeUsersCount, totalAdvance, totalPenalty, totalConsumerCount, + consumerCount, lastDemandGenratedDate, noOfDemandRaised, totaldemAmount, + collectionsMade, lastCollectionDate, expenseCount, + countOfElectricityExpenseBills, noOfPaidExpenseBills, lastExpTrnsDate, + totalAmountOfExpenseBills, totalAmountOfElectricityBills, + totalAmountOfPaidExpenseBills, date,tenantName): + # url = 'http://localhost:8080/ws-calculator/waterCalculator/_rollOutDashboardSearch' + rollOut_headers = {'Content-Type': 'application/json'} + url = os.getenv('WS_API_URL') + + if not url: + print("API_URL environment variable is not set.") + return + + requestData = { + "RequestInfo": { + "apiId": "Rainmaker", + "action": "", + "did": 1, + "key": "", + "msgId": "20170310130900|en_IN", + "requesterId": "", + "ts": 1513579888683, + "ver": ".01", + "authToken": "572ad571-9061-444e-bcdb-84061b61f467" + }, + "rollOutDashboard": { + "id": 1, + "tenantid": tenant['tenantId'], + "projectcode": tenant['projectcode'], + "zone": tenant['zone'], + "circle": tenant['circle'], + "division": tenant['division'], + "subdivision": tenant['subdivision'], + "section": tenant['section'], + "activeUsersCount": activeUsersCount, + "totalAdvance": convert_decimal_to_float(totalAdvance), + "totalPenalty": convert_decimal_to_float(totalPenalty), + "totalConnections": totalConsumerCount, + "activeConnections": consumerCount, + "lastDemandGenDate": convert_date_to_string(lastDemandGenratedDate), + "demandGeneratedConsumerCount": noOfDemandRaised, + "totalDemandAmount": convert_decimal_to_float(totaldemAmount), + "collectionTillDate": convert_decimal_to_float(collectionsMade), + "lastCollectionDate": convert_date_to_string(lastCollectionDate), + "expenseCount": expenseCount, + "countOfElectricityExpenseBills": countOfElectricityExpenseBills, + "noOfPaidExpenseBills": noOfPaidExpenseBills, + "lastExpenseTxnDate": convert_date_to_string(lastExpTrnsDate), + "totalAmountOfExpenseBills": convert_decimal_to_float(totalAmountOfExpenseBills), + "totalAmountOfElectricityBills": convert_decimal_to_float(totalAmountOfElectricityBills), + "totalAmountOfPaidExpenseBills": convert_decimal_to_float(totalAmountOfPaidExpenseBills), + "dateRange": date, + "tenantName": tenantName + } + } + + print(requestData) + + try: + response = requests.post(url + 'ws-calculator/waterCalculator/_rollOutDashboardSearch', headers=rollOut_headers, + json=requestData) + if response.status_code == 200: + print("Successfully inserted data for tenant " + tenant['tenantId'] + " and date range " + date) + else: + print("Failed to insert data for tenant " + tenant['tenantId'] + " and date range " + date) + print("Response:", response.json()) + except Exception as e: + print("An error occurred:") + print(e) + + +def process(): + print("continue is the process") + + try: + connection = getConnection() + cursor = connection.cursor() + + print("cursor: ", cursor) + + DROPPING_TABLE_QUERY = " drop table if exists roll_out_dashboard " + cursor.execute(DROPPING_TABLE_QUERY) + + connection.commit() + + createTableQuery = createTable() + cursor.execute(createTableQuery) + + connection.commit() + + print("table dropped") + except Exception as exception: + print("Exception occurred while connecting to the database") + print(exception) + + finally: + if connection: + cursor.close() + connection.close() + + tenants = getGPWSCHeirarchy() + for tenant in tenants: + print("Tenant:", tenant['tenantId']) + tenantName = tenant['tenantName'] + print("Tenant Name:", tenantName) + activeUsersCount = getActiveUsersCount(tenant['tenantId']) + daterange = ['Consolidated (As on date)'] + for i, date in enumerate(daterange): + startdate, enddate = getdaterange(date) + + totalConsumerCount = getTotalConsumerCount(tenant['tenantId'], startdate, enddate) + if totalConsumerCount > 0: + totaldemAmount = getTotalDemandAmount(tenant['tenantId'], startdate, enddate) + totalAdvance = getTotalAdvanceCreated(tenant['tenantId'], startdate, enddate) + totalPenalty = getTotalPenaltyCreated(tenant['tenantId'], startdate, enddate) + lastDemandGenratedDate = getLastDemandDate(tenant['tenantId'], startdate, enddate) + noOfDemandRaised = getTotalDemandRaised(tenant['tenantId'], startdate, enddate) + lastCollectionDate = getLastCollectionDate(tenant['tenantId'], startdate, enddate) + collectionsMade = getCollectionsMade(tenant['tenantId'], startdate, enddate) + consumerCount = getConsumersCount(tenant['tenantId'], startdate, enddate) + else: + totaldemAmount = 0.0 + totalAdvance = 0.0 + totalPenalty = 0.0 + lastDemandGenratedDate = None + noOfDemandRaised = 0 + lastCollectionDate = None + collectionsMade = 0.0 + consumerCount = 0 + + totalAmountOfExpenseBills = getTotalAmountExpenseBills(tenant['tenantId'], startdate, enddate) + + if totalAmountOfExpenseBills is not None and totalAmountOfExpenseBills > 0: + # totalAmountOfExpenseBills = getTotalAmountExpenseBills(tenant['tenantId'], startdate, enddate) + totalAmountOfElectricityBills = getTotalAmountElectricityBills(tenant['tenantId'], startdate, enddate) + totalAmountOfPaidExpenseBills = getTotalAmountPaidBills(tenant['tenantId'], startdate, enddate) + countOfElectricityExpenseBills = getElectricityExpenseBillEntered(tenant['tenantId'], startdate,enddate) + lastExpTrnsDate = getLastExpTransactionDate(tenant['tenantId'], startdate, enddate) + noOfPaidExpenseBills = getNoOfBillsPaid(tenant['tenantId'], startdate, enddate) + else: + # totalAmountOfExpenseBills = 0.0 + totalAmountOfElectricityBills = 0.0 + totalAmountOfPaidExpenseBills = 0.0 + countOfElectricityExpenseBills = 0 + lastExpTrnsDate = None + noOfPaidExpenseBills = 0 + + expenseCount = getExpenseBillEntered(tenant['tenantId'], startdate, enddate) + # createEntryForRollout(tenant,activeUsersCount,totalAdvance, totalPenalty,totalConsumerCount,consumerCount,lastDemandGenratedDate,noOfDemandRaised,totaldemAmount,collectionsMade,lastCollectionDate, expenseCount,countOfElectricityExpenseBills,noOfPaidExpenseBills, lastExpTrnsDate, totalAmountOfExpenseBills, totalAmountOfElectricityBills, totalAmountOfPaidExpenseBills,date) + createEntryForRolloutToElasticSearch(tenant, activeUsersCount, totalAdvance, totalPenalty, + totalConsumerCount, + consumerCount, lastDemandGenratedDate, noOfDemandRaised, + totaldemAmount, + collectionsMade, lastCollectionDate, expenseCount, + countOfElectricityExpenseBills, + noOfPaidExpenseBills, lastExpTrnsDate, totalAmountOfExpenseBills, + totalAmountOfElectricityBills, totalAmountOfPaidExpenseBills, date,tenantName) + print("End of rollout dashboard") + return + + +def getConnection(): + dbHost = os.getenv('DB_HOST') + dbSchema = os.getenv('DB_SCHEMA') + dbUser = os.getenv('DB_USER') + dbPassword = os.getenv('DB_PWD') + dbPort = os.getenv('DB_PORT') + + connection = psycopg2.connect(user=dbUser, + password=dbPassword, + host=dbHost, + port=dbPort, + database=dbSchema) + + return connection + + +def getCurrentDate(): + currentDate = datetime.today().strftime('%Y-%m-%d') + currentDateInMillis = str(parser.parse(currentDate).timestamp() * 1000) + + return currentDateInMillis + + +def createTable(): + CREATE_TABLE_QUERY = """create table roll_out_dashboard( + id SERIAL primary key, + tenantid varchar(250) NOT NULL, + projectcode varchar(66), + zone varchar(250), + circle varchar(250), + division varchar(250), + subdivision varchar(250), + section varchar(250), + active_users_count NUMERIC(10), + total_advance NUMERIC(10), + total_penalty NUMERIC(10), + total_connections NUMERIC(10), + active_connections NUMERIC(10), + last_demand_gen_date DATE, + demand_generated_consumer_count NUMERIC(10), + total_demand_amount NUMERIC(10), + collection_till_date NUMERIC(12, 2), + last_collection_date DATE, + expense_count BIGINT, + count_of_electricity_expense_bills BIGINT, + no_of_paid_expense_bills BIGINT, + last_expense_txn_date Date, + total_amount_of_expense_bills BIGINT, + total_amount_of_electricity_bills BIGINT, + total_amount_of_paid_expense_bills BIGINT, + date_range varchar(250), + createdtime TIMESTAMP NOT NULL + )""" + + return CREATE_TABLE_QUERY + + +if __name__ == '__main__': + process() \ No newline at end of file diff --git a/utilities/rollout-dashboard-cronjob-indexer/requirements.txt b/utilities/rollout-dashboard-cronjob-indexer/requirements.txt new file mode 100644 index 000000000..6e9c7665b --- /dev/null +++ b/utilities/rollout-dashboard-cronjob-indexer/requirements.txt @@ -0,0 +1,13 @@ +asn1crypto==0.24.0 +enum34==1.1.6 +idna==2.6 +ipaddress==1.0.17 +keyring==10.6.0 +keyrings.alt==3.0 +pyxdg==0.25 +SecretStorage==2.3.1 +six==1.16.0 +requests +python-dateutil +psycopg2 +pytz