From 235cb3e33d65adbfac980b5d59dd8fc9991ae033 Mon Sep 17 00:00:00 2001 From: tanishi-egov Date: Mon, 27 Jan 2025 12:55:20 +0530 Subject: [PATCH] [HCMPRE-857, HCMPRE-1139, HCMPRE-1303, HCMPRE-1158] Changes in hrms-service for email notification feature, UUID and role search changes, Pagination and case insensitive fuzzy search in user name (#1337) * Total count enhancement in HRMS * Corrected count query logic * Fixed HRMS total count * Fixed hrms uuids search * Fixed HRMS search response * added email notification service * added email notification service * changing implementation partner * Adding last modified date sorting clause in HRMS search query * Adding case insensitive search * Revert "Adding last modified date sorting clause in HRMS search query" This reverts commit c287376b759178dca2db0803a1d18d18f8121ca0. * changing implementation partner * HCMPRE-1333- Removed dense rank query; using sequential calls to get child table data. (#1210) * Revert "HCMPRE-1333- Removed dense rank query; using sequential calls to get child table data. (#1210)" This reverts commit 2d2d4ccf917441412f1a49562d257ca65c2a4496. * Added comments and resolved some coderabbit review comments * Removing IndividualBulkResponse class and importing from library * updating version for org.egov.services.services-common * using IndividualBulkResponse class in egov-hrms --------- Co-authored-by: Shashwat Mishra Co-authored-by: Shashwat Mishra <71879793+shashwat-egov@users.noreply.github.com> Co-authored-by: shubhang-eGov <70943369+shubhang-eGov@users.noreply.github.com> --- core-services/egov-hrms/pom.xml | 2 +- .../egov/hrms/config/PropertiesManager.java | 18 +- .../org/egov/hrms/consumer/HrmsConsumer.java | 11 +- .../egov/hrms/service/EmployeeService.java | 39 ++++- .../egov/hrms/service/IndividualService.java | 5 +- .../hrms/service/NotificationService.java | 44 ++++- .../org/egov/hrms/utils/HRMSConstants.java | 3 + .../org/egov/hrms/utils/NotificationUtil.java | 154 ++++++++++++++++++ .../org/egov/hrms/web/contract/Email.java | 31 ++++ .../egov/hrms/web/contract/EmailRequest.java | 16 ++ .../hrms/web/contract/EmployeeResponse.java | 5 + .../web/contract/EmployeeSearchCriteria.java | 34 ++-- .../egov/hrms/web/contract/UserResponse.java | 5 + .../web/models/IndividualBulkResponse.java | 54 ++++++ .../src/main/resources/application.properties | 9 + .../repository/IndividualRepository.java | 4 +- 16 files changed, 401 insertions(+), 33 deletions(-) create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/utils/NotificationUtil.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/Email.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmailRequest.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/IndividualBulkResponse.java diff --git a/core-services/egov-hrms/pom.xml b/core-services/egov-hrms/pom.xml index 0a0507aa5a4..ff717d747cc 100644 --- a/core-services/egov-hrms/pom.xml +++ b/core-services/egov-hrms/pom.xml @@ -39,11 +39,11 @@ org.flywaydb flyway-core - 9.22.3 org.postgresql postgresql + 42.7.1 org.egov.services diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/config/PropertiesManager.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/config/PropertiesManager.java index 1f0522f0d36..14e911985c0 100644 --- a/core-services/egov-hrms/src/main/java/org/egov/hrms/config/PropertiesManager.java +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/config/PropertiesManager.java @@ -82,7 +82,13 @@ public class PropertiesManager { @Value("${egov.idgen.path}") public String idGenEndpoint; - + + // Email + @Value("${kafka.topics.notification.email}") + private String emailNotifTopic; + + @Value("${notification.email.enabled}") + private Boolean isEmailNotificationEnabled; //Kafka Topics @Value("${kafka.topics.save.service}") @@ -96,7 +102,9 @@ public class PropertiesManager { @Value("${kafka.topics.hrms.updateData}") public String updateTopic; - + + @Value("${kafka.topics.hrms.email.notification}") + public String hrmsEmailNotifTopic; //Variables @Value("${egov.idgen.ack.name}") @@ -140,4 +148,10 @@ public class PropertiesManager { @Value("${egov.boundary.search.url}") private String boundarySearchUrl; + + @Value("${hrms.email.notification.implementation.partner}") + public String emailNotificationImplementationPartner; + + @Value("${hrms.email.notification.website.link}") + public String emailNotificationWebsiteLink; } \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/consumer/HrmsConsumer.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/consumer/HrmsConsumer.java index a4c33b0c096..74b2360cd73 100644 --- a/core-services/egov-hrms/src/main/java/org/egov/hrms/consumer/HrmsConsumer.java +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/consumer/HrmsConsumer.java @@ -32,12 +32,17 @@ public class HrmsConsumer { @Autowired private PropertiesManager propertiesManager; - @KafkaListener(topics = {"${kafka.topics.hrms.updateData}"}) + @KafkaListener(topics = {"${kafka.topics.hrms.updateData}", "${kafka.topics.hrms.email.notification}"}) public void listenUpdateEmployeeData(final HashMap record,@Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { try { EmployeeRequest employeeRequest = mapper.convertValue(record, EmployeeRequest.class); - hrmsProducer.push(propertiesManager.getUpdateEmployeeTopic(), employeeRequest); - notificationService.sendReactivationNotification(employeeRequest); + + if(topic.equals(propertiesManager.getHrmsEmailNotifTopic())) { + notificationService.processEmailNotification(employeeRequest); + } else { + hrmsProducer.push(propertiesManager.getUpdateEmployeeTopic(), employeeRequest); + notificationService.sendReactivationNotification(employeeRequest); + } } catch (final Exception e) { log.error("Error while listening to value: " + record + " on topic: " + topic + ": ", e); diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/service/EmployeeService.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/EmployeeService.java index 2cecd5f5f71..c42d487fa2d 100644 --- a/core-services/egov-hrms/src/main/java/org/egov/hrms/service/EmployeeService.java +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/EmployeeService.java @@ -121,8 +121,12 @@ public EmployeeResponse create(EmployeeRequest employeeRequest) { enrichCreateRequest(employee, requestInfo); createUser(employee, requestInfo); pwdMap.put(employee.getUuid(), employee.getUser().getPassword()); - employee.getUser().setPassword(null); }); + hrmsProducer.push(propertiesManager.getHrmsEmailNotifTopic(), employeeRequest); + + // Setting password as null after sending employeeRequest to email notification topic to send email. + employeeRequest.getEmployees().forEach(employee -> employee.getUser().setPassword(null)); + hrmsProducer.push(propertiesManager.getSaveEmployeeTopic(), employeeRequest); notificationService.sendNotification(employeeRequest, pwdMap); return generateResponse(employeeRequest); @@ -137,6 +141,7 @@ public EmployeeResponse create(EmployeeRequest employeeRequest) { */ public EmployeeResponse search(EmployeeSearchCriteria criteria, RequestInfo requestInfo) { boolean userChecked = false; + Long totalCount = 0L; /*if(null == criteria.getIsActive() || criteria.getIsActive()) criteria.setIsActive(true); else @@ -156,6 +161,7 @@ public EmployeeResponse search(EmployeeSearchCriteria criteria, RequestInfo requ userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_USERNAME, criteria.getCodes().get(0)); } UserResponse userResponse = userService.getUser(requestInfo, userSearchCriteria); + totalCount = userResponse.getTotalCount(); userChecked =true; if(!CollectionUtils.isEmpty(userResponse.getUser())) { mapOfUsers.putAll(userResponse.getUser().stream() @@ -178,6 +184,7 @@ public EmployeeResponse search(EmployeeSearchCriteria criteria, RequestInfo requ userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_TENANTID,criteria.getTenantId()); userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_NAME,name); UserResponse userResponse = userService.getUser(requestInfo, userSearchCriteria); + totalCount = userResponse.getTotalCount(); userChecked =true; if(!CollectionUtils.isEmpty(userResponse.getUser())) { mapOfUsers.putAll(userResponse.getUser().stream() @@ -191,6 +198,32 @@ public EmployeeResponse search(EmployeeSearchCriteria criteria, RequestInfo requ else criteria.setUuids(userUUIDs); } + + if(!CollectionUtils.isEmpty(criteria.getUserServiceUuids())) { + List userUUIDs = new ArrayList<>(); + Map userSearchCriteria = new HashMap<>(); + + userSearchCriteria.put(HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE_CODE, HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_TENANTID, criteria.getTenantId()); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_USER_SERVICE_UUIDS, criteria.getUserServiceUuids()); + if(!CollectionUtils.isEmpty(criteria.getNames())) + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_NAME, criteria.getNames().get(0)); + UserResponse userResponse = userService.getUser(requestInfo, userSearchCriteria); + totalCount = userResponse.getTotalCount(); + userChecked =true; + if(!CollectionUtils.isEmpty(userResponse.getUser())) { + mapOfUsers.putAll(userResponse.getUser().stream() + .collect(Collectors.toMap(User::getUuid, Function.identity()))); + } + + List uuids = userResponse.getUser().stream().map(User :: getUuid).collect(Collectors.toList()); + userUUIDs.addAll(uuids); + + if(!CollectionUtils.isEmpty(criteria.getUuids())) + criteria.setUuids(criteria.getUuids().stream().filter(userUUIDs::contains).collect(Collectors.toList())); + else + criteria.setUuids(userUUIDs); + } } if(userChecked) criteria.setTenantId(null); @@ -207,6 +240,7 @@ public EmployeeResponse search(EmployeeSearchCriteria criteria, RequestInfo requ if(mapOfUsers.isEmpty()){ log.info("searching in user service"); UserResponse userResponse = userService.getUser(requestInfo, userSearchCriteria); + totalCount = userResponse.getTotalCount(); if(!CollectionUtils.isEmpty(userResponse.getUser())) { mapOfUsers = userResponse.getUser().stream() .collect(Collectors.toMap(User :: getUuid, Function.identity())); @@ -217,7 +251,8 @@ public EmployeeResponse search(EmployeeSearchCriteria criteria, RequestInfo requ } } return EmployeeResponse.builder().responseInfo(factory.createResponseInfoFromRequestInfo(requestInfo, true)) - .employees(employees).build(); + .employees(employees) + .totalCount(totalCount).build(); } diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/service/IndividualService.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/IndividualService.java index 6a967bf8cfb..40482914921 100644 --- a/core-services/egov-hrms/src/main/java/org/egov/hrms/service/IndividualService.java +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/IndividualService.java @@ -22,7 +22,6 @@ import org.egov.common.models.individual.Gender; import org.egov.common.models.individual.Identifier; import org.egov.common.models.individual.Individual; -import org.egov.common.models.individual.IndividualBulkResponse; import org.egov.common.models.individual.IndividualRequest; import org.egov.common.models.individual.IndividualResponse; import org.egov.common.models.individual.Name; @@ -33,10 +32,12 @@ import org.egov.hrms.web.contract.User; import org.egov.hrms.web.contract.UserRequest; import org.egov.hrms.web.contract.UserResponse; +import org.egov.hrms.web.models.IndividualBulkResponse; import org.egov.hrms.web.models.IndividualSearch; import org.egov.hrms.web.models.IndividualSearchRequest; import org.springframework.beans.factory.annotation.Autowired; +import static org.egov.hrms.utils.HRMSConstants.HRMS_USER_SEARCH_CRITERA_USER_SERVICE_UUIDS; import static org.egov.hrms.utils.HRMSConstants.SYSTEM_GENERATED; @Slf4j @@ -210,6 +211,7 @@ public UserResponse getUser(RequestInfo requestInfo, Map userSea mobileNumberList ) .id((List) userSearchCriteria.get("uuid")) + .userUuid((List) userSearchCriteria.get(HRMS_USER_SEARCH_CRITERA_USER_SERVICE_UUIDS)) .roleCodes((List) userSearchCriteria.get("roleCodes")) .username(usernameList) // given name @@ -331,6 +333,7 @@ private static UserResponse mapToUserResponse(IndividualBulkResponse response) { .responseInfo(response.getResponseInfo()) .user(response.getIndividual().stream() .map(IndividualService::getUser).collect(Collectors.toList())) + .totalCount(response.getTotalCount()) .build(); return userResponse; } diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/service/NotificationService.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/NotificationService.java index acb427e4ce7..a8915e3983c 100644 --- a/core-services/egov-hrms/src/main/java/org/egov/hrms/service/NotificationService.java +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/NotificationService.java @@ -11,30 +11,40 @@ import org.egov.hrms.producer.HRMSProducer; import org.egov.hrms.repository.RestCallRepository; import org.egov.hrms.utils.HRMSConstants; +import org.egov.hrms.utils.NotificationUtil; +import org.egov.hrms.web.contract.EmailRequest; import org.egov.hrms.web.contract.EmployeeRequest; import org.egov.hrms.web.contract.RequestInfoWrapper; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import com.jayway.jsonpath.JsonPath; import lombok.extern.slf4j.Slf4j; +import org.springframework.util.CollectionUtils; import org.springframework.web.client.RestTemplate; +import static org.egov.hrms.utils.HRMSConstants.HEALTH_HRMS_EMAIL_LOCALIZATION_CODE; + @Service @Slf4j public class NotificationService { - - @Autowired + private HRMSProducer producer; - - @Autowired + private RestCallRepository repository; - @Autowired private RestTemplate restTemplate; + private NotificationUtil notificationUtil; + + public NotificationService(HRMSProducer producer, RestCallRepository repository, RestTemplate restTemplate, NotificationUtil notificationUtil) { + this.producer = producer; + this.repository = repository; + this.restTemplate = restTemplate; + this.notificationUtil = notificationUtil; + } + @Value("${kafka.topics.notification.sms}") private String smsTopic; @@ -193,4 +203,26 @@ public Map> getLocalisedMessages(RequestInfo request return localizedMessageMap; } + /** + * Creates and sends email notification to the employees whose details are provided in the employeeRequest. + * + * @param employeeRequest The employee request with employee details. + */ + public void processEmailNotification(EmployeeRequest employeeRequest) { + if (employeeRequest == null || CollectionUtils.isEmpty(employeeRequest.getEmployees())) { + log.error("Invalid employee request received for email notification"); + return; + } + try { + // Fetch localization messages and get email message template for HEALTH_HRMS_EMAIL_LOCALIZATION_CODE template code. + String localizationMessages = notificationUtil.getLocalizationMessages(employeeRequest); + String messageTemplate = notificationUtil.getMessageTemplate(HEALTH_HRMS_EMAIL_LOCALIZATION_CODE, localizationMessages); + + // Create email requests from the employee details provided in the employeeRequest. + List emailRequests = notificationUtil.createEmailRequest(employeeRequest, messageTemplate); + notificationUtil.sendEmail(emailRequests); + } catch (Exception e) { + log.error("Error processing email notification for given employees"); + } + } } diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/HRMSConstants.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/HRMSConstants.java index 0d01b642d97..34ef1076fdb 100644 --- a/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/HRMSConstants.java +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/HRMSConstants.java @@ -30,6 +30,8 @@ public class HRMSConstants { public static final String HRMS_EMP_CREATE_LOCLZN_CODE = "hrms.employee.create.notification"; public static final String HRMS_EMP_REACTIVATE_LOCLZN_CODE = "hrms.employee.reactivation.notification"; public static final String HRMS_LOCALIZATION_MODULE_CODE = "egov-hrms"; + public static final String HEALTH_HRMS_LOCALIZATION_MODULE_CODE = "rainmaker-hr"; + public static final String HEALTH_HRMS_EMAIL_LOCALIZATION_CODE = "HEALTH_HRMS_EMAIL_CODE"; public static final String HRMS_LOCALIZATION_ENG_LOCALE_CODE = "en_IN"; public static final String HRMS_TENANTBOUNDARY_HIERARCHY_JSONPATH = "$.TenantBoundary[?(@.boundary.code ==\"%s\")].hierarchyType.code"; public static final String HRMS_TENANTBOUNDARY_BOUNDARY_TYPE_JSONPATH ="$.TenantBoundary[?(@.hierarchyType.name==\"%1$s\" && @.boundary.code ==\"%2$s\")]..label"; @@ -39,6 +41,7 @@ public class HRMSConstants { public static final String HRMS_MDMS_CODE_FLITER = "[?(@.active == true)].code"; public static final String HRMS_USER_SEARCH_CRITERA_UUID = "uuid"; + public static final String HRMS_USER_SEARCH_CRITERA_USER_SERVICE_UUIDS = "userServiceUuids"; public static final String HRMS_USER_SEARCH_CRITERA_ROLECODES = "roleCodes"; public static final String HRMS_USER_SEARCH_CRITERA_TENANTID = "tenantId"; public static final String HRMS_USER_SEARCH_CRITERA_MOBILENO = "mobileNumber"; diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/NotificationUtil.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/NotificationUtil.java new file mode 100644 index 00000000000..22b8ea41493 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/NotificationUtil.java @@ -0,0 +1,154 @@ +package org.egov.hrms.utils; + +import com.jayway.jsonpath.JsonPath; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestInfo; +import org.egov.hrms.config.PropertiesManager; +import org.egov.hrms.model.Employee; +import org.egov.hrms.producer.HRMSProducer; +import org.egov.hrms.repository.RestCallRepository; +import org.egov.hrms.web.contract.Email; +import org.egov.hrms.web.contract.EmailRequest; +import org.egov.hrms.web.contract.EmployeeRequest; +import org.egov.hrms.web.contract.RequestInfoWrapper; +import org.json.JSONObject; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; + +import static org.egov.hrms.utils.HRMSConstants.*; + +@Slf4j +@Component +public class NotificationUtil { + + private RestCallRepository restCallRepository; + + private PropertiesManager propertiesManager; + + private HRMSProducer producer; + + public NotificationUtil(RestCallRepository restCallRepository, PropertiesManager propertiesManager, HRMSProducer producer) { + this.restCallRepository = restCallRepository; + this.propertiesManager = propertiesManager; + this.producer = producer; + } + + /** + * Extracts message for the specific code from the localization messages. + * + * @param notificationCode The code for which message is required. + * @param localizationMessage The localization messages. + * @return message for the specific code. + */ + public String getMessageTemplate(String notificationCode, String localizationMessage) { + // Create the path to get the message for the provided notification code from localization messages. + String path = "$..messages[?(@.code==\"{}\")].message"; + path = path.replace("{}", notificationCode); + String message = null; + try { + // Tries to get the message for the provided notificationCode. + List data = JsonPath.parse(localizationMessage).read(path); + if (!CollectionUtils.isEmpty(data)) + message = data.get(0).toString(); + else + log.error("Fetching from localization failed with code " + notificationCode); + } catch (Exception e) { + log.warn("Fetching from localization failed", e); + } + return message; + } + + /** + * Fetches all the localization messages from localization service. + * + * @param employeeRequest The employee request + * @return Localization messages for the module + */ + public String getLocalizationMessages(EmployeeRequest employeeRequest) { + + RequestInfoWrapper requestInfoWrapper = new RequestInfoWrapper(); + requestInfoWrapper.setRequestInfo(employeeRequest.getRequestInfo()); + + LinkedHashMap responseMap = (LinkedHashMap) restCallRepository.fetchResult(getUri(employeeRequest), requestInfoWrapper); + return new JSONObject(responseMap).toString(); + } + + /** + * Returns the search uri for the localization search to get localization messages from "rainmaker-hr" module. + * + * @param employeeRequest The employee request with locale code. + * @return The uri for localization search call. + */ + public StringBuilder getUri(EmployeeRequest employeeRequest) { + String tenantId = employeeRequest.getEmployees().get(0).getTenantId().split("\\.")[0]; + + String locale = HRMS_LOCALIZATION_ENG_LOCALE_CODE; + if (!StringUtils.isEmpty(employeeRequest.getRequestInfo().getMsgId()) && employeeRequest.getRequestInfo().getMsgId().split("|").length >= 2) + locale = employeeRequest.getRequestInfo().getMsgId().split("\\|")[1]; + + StringBuilder uri = new StringBuilder(); + uri.append(propertiesManager.getLocalizationHost()).append(propertiesManager.getLocalizationSearchEndpoint()) + .append("?").append("locale=").append(locale).append("&tenantId=").append(tenantId).append("&module=").append(HEALTH_HRMS_LOCALIZATION_MODULE_CODE); + + return uri; + } + + /** + * Replaces the placeholders from the email template and creates an email request from the given employee request. + * + * + * @param employeeRequest The employee request + * @param emailTemplate the email template + * @return The list of email requests + */ + public List createEmailRequest(EmployeeRequest employeeRequest, String emailTemplate) { + RequestInfo requestInfo = employeeRequest.getRequestInfo(); + + List emailRequest = new LinkedList<>(); + + // Iterate over each employee details and create email request for each employee. + for (Employee employee : employeeRequest.getEmployees()) { + String customizedMsg = emailTemplate.replace("{User's name}", employee.getUser().getName()); + customizedMsg = customizedMsg.replace("{Username}", employee.getCode()); + customizedMsg = customizedMsg.replace("{Password}", employee.getUser().getPassword()); + customizedMsg = customizedMsg.replace("{website URL}", propertiesManager.getEmailNotificationWebsiteLink()); + customizedMsg = customizedMsg.replace("{Implementation partner}", propertiesManager.getEmailNotificationImplementationPartner()); + + // Get email subject and email body from the provided email template. + String subject = customizedMsg.substring(customizedMsg.indexOf("

")+4, customizedMsg.indexOf("

")); + String body = customizedMsg.substring(customizedMsg.indexOf("")+5); + + // Create the email object with the employee's email id, subject and customized email body created. + Email emailObj = Email.builder().emailTo(Collections.singleton(employee.getUser().getEmailId())).isHTML(true).body(body).subject(subject).build(); + EmailRequest email = new EmailRequest(requestInfo, emailObj); + emailRequest.add(email); + } + return emailRequest; + } + + /** + * Pushes email request list into email notification topic if email notification is enabled. + * + * @param emailRequestList The list of emailRequests. + */ + public void sendEmail(List emailRequestList) { + if (propertiesManager.getIsEmailNotificationEnabled()) { + if (CollectionUtils.isEmpty(emailRequestList)) { + log.error("No Emails Found!"); + } else { + // Iterate over each email and push them into emailNotifTopic to send emails. + for (EmailRequest emailRequest : emailRequestList) { + producer.push(propertiesManager.getEmailNotifTopic(), emailRequest); + log.info("Email Request -> " + emailRequest.toString()); + log.info("EMAIL notification sent!"); + } + } + } + } +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/Email.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/Email.java new file mode 100644 index 00000000000..68c6011e4e4 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/Email.java @@ -0,0 +1,31 @@ +package org.egov.hrms.web.contract; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Set; + +@Setter +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Data +@Builder +public class Email { + + @NotNull + @Size(min = 1, message = "At least one recipient is required") + private Set emailTo; + + @NotBlank(message = "Subject is required") + private String subject; + + @NotBlank(message = "Body is required") + private String body; + @JsonProperty("isHTML") + private boolean isHTML; + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmailRequest.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmailRequest.java new file mode 100644 index 00000000000..015b31217b1 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmailRequest.java @@ -0,0 +1,16 @@ +package org.egov.hrms.web.contract; + +import lombok.*; +import org.egov.common.contract.request.RequestInfo; + +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Setter +@Getter +@ToString +public class EmailRequest { + + private RequestInfo requestInfo; + private Email email; +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeResponse.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeResponse.java index 6fb5141aeed..df8fb1538e5 100644 --- a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeResponse.java +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeResponse.java @@ -54,6 +54,7 @@ import lombok.NoArgsConstructor; import lombok.Setter; import lombok.ToString; + @Builder @AllArgsConstructor @EqualsAndHashCode @@ -69,4 +70,8 @@ public class EmployeeResponse { @JsonProperty("Employees") private List employees; + @JsonProperty("TotalCount") + @Builder.Default + private Long totalCount = 0L; + } \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeSearchCriteria.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeSearchCriteria.java index f5a3f9dfca6..052f98a7072 100644 --- a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeSearchCriteria.java +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeSearchCriteria.java @@ -23,38 +23,40 @@ @Builder public class EmployeeSearchCriteria { - public List codes; + private List codes; - public List names; + private List names; - public List departments; + private List departments; - public List designations; + private List designations; - public Long asOnDate; + private Long asOnDate; - public List roles; + private List roles; - public List ids; + private List ids; - public List employeestatuses; + private List employeestatuses; - public List employeetypes; + private List employeetypes; - public List uuids; + private List uuids; + + private List userServiceUuids; - public List positions; + private List positions; - public Boolean isActive; + private Boolean isActive; @Size(max = 250) - public String tenantId; + private String tenantId; - public String phone; + private String phone; - public Integer offset; + private Integer offset; - public Integer limit; + private Integer limit; private Boolean includeUnassigned = false; diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/UserResponse.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/UserResponse.java index 285964a0a87..ea727df4cbd 100644 --- a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/UserResponse.java +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/UserResponse.java @@ -43,6 +43,7 @@ import java.util.ArrayList; import java.util.List; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Builder; import org.egov.common.contract.response.ResponseInfo; @@ -66,4 +67,8 @@ public class UserResponse { private List user = new ArrayList(); + @JsonIgnore + @Builder.Default + private Long totalCount = 0L; + } \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/IndividualBulkResponse.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/IndividualBulkResponse.java new file mode 100644 index 00000000000..845d6cb72d0 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/IndividualBulkResponse.java @@ -0,0 +1,54 @@ +package org.egov.hrms.web.models; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +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 org.egov.common.models.individual.Individual; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +/** + * IndividualBulkResponse + */ +@Validated + + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class IndividualBulkResponse { + + @JsonProperty("ResponseInfo") + @NotNull + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + + @JsonProperty("Individual") + @Valid + private List individual = null; + + public IndividualBulkResponse addIndividualItem(Individual individualItem) { + if (this.individual == null) { + this.individual = new ArrayList<>(); + } + this.individual.add(individualItem); + return this; + } + +} diff --git a/core-services/egov-hrms/src/main/resources/application.properties b/core-services/egov-hrms/src/main/resources/application.properties index dcece925352..6333f704295 100644 --- a/core-services/egov-hrms/src/main/resources/application.properties +++ b/core-services/egov-hrms/src/main/resources/application.properties @@ -65,6 +65,7 @@ egov.individual.host=https://health-dev.digit.org egov.individual.create.endpoint=/individual/v1/_create egov.individual.update.endpoint=/individual/v1/_update egov.individual.search.endpoint=/individual/v1/_search +egov.individual.delete.endpoint=/individual/v1/_delete # use qualifier as "defaultUserService" to integrate with egov-user module # use qualifier as "individualService" to integrate with individual module @@ -101,7 +102,9 @@ spring.kafka.producer.value-serializer=org.springframework.kafka.support.seriali kafka.topics.save.service=save-hrms-employee kafka.topics.update.service=update-hrms-employee kafka.topics.notification.sms=egov.core.notification.sms +kafka.topics.notification.email=egov.core.notification.email kafka.topics.hrms.updateData= egov-hrms-update +kafka.topics.hrms.email.notification=hrms-send-email-notification spring.kafka.listener.missing-topics-fatal=false @@ -117,6 +120,12 @@ state.level.tenant.id=default egov.hrms.auto.generate.password=true +# EMAIL NOTIFICATION CONFIG +notification.email.enabled=true + +hrms.email.notification.implementation.partner=NMCP Mozambique +hrms.email.notification.website.link=https://unified-qa.digit.org/microplan-ui + # BOUNDARY SERVICE egov.boundary.host=http://localhost:8081 egov.boundary.search.url=/boundary-service/boundary/_search diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java index 703b5521652..8b9ef49d763 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java @@ -98,7 +98,7 @@ public SearchResponse find(IndividualSearch searchObject, Integer li return findByRadius(query, searchObject, includeDeleted, paramsMap); } if (searchObject.getIdentifier() == null) { - String queryWithoutLimit = query.replace("ORDER BY id ASC LIMIT :limit OFFSET :offset", ""); + String queryWithoutLimit = query.replace("ORDER BY createdtime DESC LIMIT :limit OFFSET :offset", ""); Long totalCount = constructTotalCountCTEAndReturnResult(queryWithoutLimit, paramsMap, this.namedParameterJdbcTemplate); List individuals = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); if (!individuals.isEmpty()) { @@ -226,7 +226,7 @@ private String getQueryForIndividual(IndividualSearch searchObject, Integer limi query = query.replace(tableName + " AND", tableName + " WHERE "); } if (searchObject.getIndividualName() != null) { - query = query + "AND givenname LIKE :individualName "; + query = query + "AND givenname ILIKE :individualName "; paramsMap.put("individualName", "%"+searchObject.getIndividualName()+"%"); } if (searchObject.getGender() != null) {