Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added configurability for recomputing attendance for muster roll update #1854

Open
wants to merge 11 commits into
base: develop
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ public class MusterRollServiceConfiguration {
private String attendanceLogEndpoint;
@Value("${works.attendance.register.search.endpoint}")
private String attendanceRegisterEndpoint;
@Value("${works.attendance.register.update.endpoint}")
private String attendanceRegisterUpdateEndpoint;
@Value("${works.attendance.register.search.limit}")
private String attendanceRegisterSearchLimit;

Expand All @@ -105,6 +107,9 @@ public class MusterRollServiceConfiguration {
@Value("${kafka.topics.notification.sms}")
private String smsNotificationTopic;

@Value("${notification.sms.enabled:false}")
private boolean sendNotificationEnabled;

//Expense Service
@Value("${works.expense.calculator.host}")
private String expenseCalculatorServiceHost;
Expand All @@ -127,6 +132,36 @@ public class MusterRollServiceConfiguration {
@Value("${works.contract.service.code}")
private String contractServiceCode;

@Value("${musterroll.update.recompute.attendance.enabled:true}")
private boolean recomputeAttendanceEnabled;

@Value("${musterroll.individual.entry.roles.enabled:false}")
private boolean individualEntryRolesEnabled;

@Value("${musterroll.validate.start.date.monday.enabled:true}")
private boolean validateStartDateMondayEnabled;

@Value("${musterroll.add.bank.account.details.enabled:true}")
private boolean addBankAccountDetails;

@Value("${musterroll.update.attendance.register.payment.status.enabled:true}")
private boolean updateAttendanceRegisterPaymentStatusEnabled;

@Value("${egov.user.host}")
private String userHost;

@Value("${egov.user.context.path}")
private String userContextPath;

@Value("${egov.user.create.path}")
private String userCreateEndpoint;

@Value("${egov.user.search.path}")
private String userSearchEndpoint;

@Value("${egov.user.update.path}")
private String userUpdateEndpoint;

@PostConstruct
public void initialize() {
TimeZone.setDefault(TimeZone.getTimeZone(timeZone));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ private StringBuilder prepareSearchQuery(MusterRollSearchCriteria searchCriteria
addClauseIfRequired(preparedStmtList, queryBuilder);
queryBuilder.append(" muster.attendance_register_id=? ");
preparedStmtList.add(searchCriteria.getRegisterId());
} else if (searchCriteria.getRegisterIds() != null && !searchCriteria.getRegisterIds().isEmpty()) {
addClauseIfRequired(preparedStmtList, queryBuilder);
queryBuilder.append(" muster.attendance_register_id IN (").append(createQuery(searchCriteria.getRegisterIds())).append(")");
addToPreparedStatement(preparedStmtList, searchCriteria.getRegisterIds());
} else if (registerIds != null && !registerIds.isEmpty()) {
addClauseIfRequired(preparedStmtList, queryBuilder);
queryBuilder.append(" muster.attendance_register_id IN (").append(createQuery(registerIds)).append(")");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ public void createAttendance(MusterRollRequest musterRollRequest, boolean isCrea
//Add all absentee individualIds as well
individualIds.addAll(absenteesList.stream().map(entry-> entry.getIndividualId()).collect(Collectors.toSet()));
List<Individual> individuals = fetchIndividualDetails(individualIds, musterRollRequest.getRequestInfo(),musterRoll.getTenantId(),musterRoll);
List<BankAccount> bankAccounts = fetchBankaccountDetails(individualIds, musterRollRequest.getRequestInfo(),musterRoll.getTenantId());

for (Map.Entry<String,List<LocalDateTime>> entry : individualExitAttendanceMap.entrySet()) {
IndividualEntry individualEntry = new IndividualEntry();
Expand Down Expand Up @@ -197,29 +196,33 @@ public void createAttendance(MusterRollRequest musterRollRequest, boolean isCrea
individualEntries.add(individualEntry);
}

// Loop through and set individual and bank account details
for (IndividualEntry entry : individualEntries) {

// Set individual details in additionalDetails
if (!CollectionUtils.isEmpty(individuals) /* && !CollectionUtils.isEmpty(bankAccounts) */) {
Individual individual = individuals.stream()
.filter(ind -> ind.getId().equalsIgnoreCase(entry.getIndividualId())).findFirst()
.orElse(null);
BankAccount bankAccount = bankAccounts.stream()
.filter(account -> account.getReferenceId().equalsIgnoreCase(entry.getIndividualId()))
.findFirst().orElse(null);

if (individual != null /* && bankAccount != null */) {
setAdditionalDetails(entry, individualEntriesFromRequest, mdmsV2Data, individual,
bankAccount, isCreate);
} else {
log.info(
"CalculationService::createAttendance::No match found in individual and bank account service for the individual id from attendance log - "
+ entry.getIndividualId());
}

}
}
if(config.isAddBankAccountDetails()) {
List<BankAccount> bankAccounts = fetchBankaccountDetails(individualIds, musterRollRequest.getRequestInfo(),musterRoll.getTenantId());
// Loop through and set individual and bank account details
for (IndividualEntry entry : individualEntries) {

// Set individual details in additionalDetails
if (!CollectionUtils.isEmpty(individuals) /* && !CollectionUtils.isEmpty(bankAccounts) */) {
Individual individual = individuals.stream()
.filter(ind -> ind.getId().equalsIgnoreCase(entry.getIndividualId())).findFirst()
.orElse(null);
BankAccount bankAccount = bankAccounts.stream()
.filter(account -> account.getReferenceId().equalsIgnoreCase(entry.getIndividualId()))
.findFirst().orElse(null);

if (individual != null /* && bankAccount != null */) {
setAdditionalDetails(entry, individualEntriesFromRequest, mdmsV2Data, individual,
bankAccount, isCreate);
} else {
log.info(
"CalculationService::createAttendance::No match found in individual and bank account service for the individual id from attendance log - "
+ entry.getIndividualId());
}

}
}
}


musterRoll.setIndividualEntries(individualEntries);
log.debug("CalculationService::createAttendance::Individuals::size::"+musterRoll.getIndividualEntries().size());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import java.util.List;
import java.util.stream.Collectors;

import static org.egov.util.MusterRollServiceConstants.ACTION_APPROVE;
import static org.egov.util.MusterRollServiceConstants.STATUS_APPROVED;

@Service
Expand Down Expand Up @@ -211,6 +212,18 @@ public MusterRollRequest updateMusterRoll(MusterRollRequest musterRollRequest) {
calculationService.updateAttendance(musterRollRequest,mdmsData);
}
workflowService.updateWorkflowStatus(musterRollRequest);
if(config.isUpdateAttendanceRegisterPaymentStatusEnabled() && musterRollRequest.getWorkflow().getAction().equals(ACTION_APPROVE)) {
AttendanceRegisterResponse attendanceRegisterResponse = musterRollServiceUtil
.fetchAttendanceRegister(musterRollRequest.getMusterRoll(), musterRollRequest.getRequestInfo());
List<AttendanceRegister> attendanceRegisters = attendanceRegisterResponse.getAttendanceRegister();
if(attendanceRegisters == null || attendanceRegisters.isEmpty()) {
log.error("No attendance registers found to update the status");
throw new CustomException("MusterRollService::updateMusterRoll::updateAttendanceRegister", "No attendance registers found to update the status");
}
AttendanceRegister attendanceRegister = attendanceRegisters.get(0);
attendanceRegister.setPaymentStatus(STATUS_APPROVED);
musterRollServiceUtil.updateAttendanceRegister(attendanceRegister, musterRollRequest.getRequestInfo());
}
musterRollProducer.push(serviceConfiguration.getUpdateMusterRollTopic(), musterRollRequest);

try {
Expand Down Expand Up @@ -270,7 +283,7 @@ private MusterRoll fetchExistingMusterRoll(MusterRoll musterRoll) {
* @return
*/
private boolean isComputeAttendance (MusterRoll musterRoll) {
if (musterRoll.getAdditionalDetails() != null) {
if (config.isRecomputeAttendanceEnabled() && musterRoll.getAdditionalDetails() != null) {
try {
JsonNode node = mapper.readTree(mapper.writeValueAsString(musterRoll.getAdditionalDetails()));
if (node.findValue(COMPUTE_ATTENDENSE) != null && StringUtils.isNotBlank(node.findValue(COMPUTE_ATTENDENSE).textValue())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public NotificationService(MusterRollProducer musterRollProducer, NotificationUt
*/
public void sendNotificationToCBO(MusterRollRequest musterRollRequest){
String action = musterRollRequest.getWorkflow().getAction();
if(!config.isSendNotificationEnabled()) return;
if(action.equalsIgnoreCase(WF_SEND_BACK_TO_CBO_CODE) || action.equalsIgnoreCase(WF_APPROVE_CODE)) {
Map<String, String> cboDetails = notificationUtil.getCBOContactPersonDetails(musterRollRequest);
String amount = notificationUtil.getExpenseAmount(musterRollRequest);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public class MusterRollServiceConstants {
public static final String ENTRY_EVENT = "ENTRY";
public static final String EXIT_EVENT = "EXIT";
public static final String STATUS_APPROVED = "APPROVED";
public static final String ACTION_APPROVE = "APPROVE";
public static final String TENANT_ID = "tenantId";
public static final String CONTRACT_NUMBER = "contractNumber";
public static final String REQUEST_INFO = "RequestInfo";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.egov.common.contract.request.RequestInfo;
import org.egov.common.contract.request.Role;
import org.egov.common.contract.user.UserDetailResponse;
import org.egov.common.models.individual.Identifier;
import org.egov.common.models.individual.Individual;
import org.egov.common.models.individual.Skill;
import org.egov.config.MusterRollServiceConfiguration;
import org.egov.tracer.model.CustomException;
import org.egov.tracer.model.ServiceCallException;
import org.egov.web.models.*;
import org.egov.works.services.common.models.bankaccounts.BankAccount;
import org.egov.works.services.common.models.bankaccounts.BankAccountDetails;
Expand All @@ -29,10 +32,12 @@

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import static org.egov.util.MusterRollServiceConstants.*;

@Component
@Slf4j
Expand All @@ -42,14 +47,19 @@ public class MusterRollServiceUtil {

private final RestTemplate restTemplate;

private final UserUtil userUtil;

private final MusterRollServiceConfiguration config;
private static final String SKILL_CODE = "skillCode";

private static final String ROLES = "roles";

@Autowired
public MusterRollServiceUtil(ObjectMapper mapper, RestTemplate restTemplate, MusterRollServiceConfiguration config) {
public MusterRollServiceUtil(ObjectMapper mapper, RestTemplate restTemplate, UserUtil userUtil, MusterRollServiceConfiguration config) {
this.mapper = mapper;
this.restTemplate = restTemplate;
this.config = config;
this.userUtil = userUtil;
this.config = config;
}

/**
Expand Down Expand Up @@ -140,6 +150,17 @@ public void populateAdditionalDetails(Object mdmsData, IndividualEntry individua
}
}

if(config.isIndividualEntryRolesEnabled()) {
UserDetailResponse userDetailResponse = userUtil.searchUsersByIndividualIds(Collections.singletonList(individualEntry.getId()));
List<String> roles = userDetailResponse.getUser().stream().findFirst()
.orElseThrow(() -> new CustomException(
"MusterRollServiceUtil::populateAdditionalDetails::USER SEARCH ERROR",
"No user found for the individual id " + individualEntry.getId())
)
.getRoles().stream().map(Role::getCode).toList();
additionalDetails.put(ROLES, roles);
}

try {
individualEntry.setAdditionalDetails(mapper.readValue(additionalDetails.toString(), Object.class));
} catch (IOException e) {
Expand Down Expand Up @@ -266,4 +287,30 @@ public AttendanceRegisterResponse fetchAttendanceRegister(MusterRoll musterRoll,
}
return attendanceRegisterResponse;
}

public AttendanceRegisterResponse updateAttendanceRegister(AttendanceRegister attendanceRegister, RequestInfo requestInfo) {
log.info("updateAttendanceRegister::Update attendance register with tenantId::" + attendanceRegister.getTenantId()
+ " and register ID: " + attendanceRegister.getId());

StringBuilder uri = new StringBuilder();
uri.append(config.getAttendanceLogHost()).append(config.getAttendanceRegisterUpdateEndpoint());

AttendanceRegisterResponse response = null;

AttendanceRegisterRequest attendanceRegisterRequest = AttendanceRegisterRequest.builder()
.attendanceRegister(Collections.singletonList(attendanceRegister))
.requestInfo(requestInfo)
.build();
try {
response = restTemplate.postForObject(uri.toString(), attendanceRegisterRequest, AttendanceRegisterResponse.class);
} catch (HttpClientErrorException e) {
throw new ServiceCallException(e.getResponseBodyAsString());
} catch (Exception e) {
Map<String, String> map = new HashMap<>();
map.put(e.getCause().getClass().getName(), e.getMessage());
throw new CustomException(map);
}

return response;
}
}
34 changes: 20 additions & 14 deletions backend/muster-roll/src/main/java/org/egov/util/UserUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
import org.egov.common.contract.request.Role;
import org.egov.common.contract.request.User;
import org.egov.common.contract.user.UserDetailResponse;
import org.egov.common.contract.user.UserSearchRequest;
import org.egov.config.MusterRollServiceConfiguration;
import org.egov.repository.ServiceRequestRepository;
import org.egov.tracer.model.CustomException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.text.ParseException;
Expand All @@ -20,26 +21,20 @@
@Component
public class UserUtil {

private final ObjectMapper mapper;

private ObjectMapper mapper;
private final ServiceRequestRepository serviceRequestRepository;

private ServiceRequestRepository serviceRequestRepository;
private final MusterRollServiceConfiguration config;

@Value("${egov.user.create.path}")
private String userCreateEndpoint;

@Value("${egov.user.search.path}")
private String userSearchEndpoint;

@Value("${egov.user.update.path}")
private String userUpdateEndpoint;
private static final String LAST_MODIFIED_DATE = "lastModifiedDate";
private static final String PWD_EXPIRY_DATE = "pwdExpiryDate";

@Autowired
public UserUtil(ObjectMapper mapper, ServiceRequestRepository serviceRequestRepository) {
public UserUtil(ObjectMapper mapper, ServiceRequestRepository serviceRequestRepository, MusterRollServiceConfiguration config) {
this.mapper = mapper;
this.serviceRequestRepository = serviceRequestRepository;
this.config = config;
}

/**
Expand All @@ -52,9 +47,9 @@ public UserUtil(ObjectMapper mapper, ServiceRequestRepository serviceRequestRepo

public UserDetailResponse userCall(Object userRequest, StringBuilder uri) {
String dobFormat = null;
if (uri.toString().contains(userSearchEndpoint) || uri.toString().contains(userUpdateEndpoint))
if (uri.toString().contains(config.getUserSearchEndpoint()) || uri.toString().contains(config.getUserUpdateEndpoint()))
dobFormat = "yyyy-MM-dd";
else if (uri.toString().contains(userCreateEndpoint))
else if (uri.toString().contains(config.getUserCreateEndpoint()))
dobFormat = "dd/MM/yyyy";
try {
LinkedHashMap responseMap = (LinkedHashMap) serviceRequestRepository.fetchResult(uri, userRequest);
Expand All @@ -65,6 +60,17 @@ else if (uri.toString().contains(userCreateEndpoint))
}
}

public UserDetailResponse searchUsersByIndividualIds(List<String> individualIds) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder
.append(config.getUserHost())
.append(config.getUserContextPath())
.append(config.getUserSearchEndpoint());
UserSearchRequest userSearchRequest = new UserSearchRequest();
userSearchRequest.setUuid(individualIds);
return userCall(userSearchRequest, stringBuilder);
}


/**
* Parses date formats to long for all users in responseMap
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ private void validateCreateMusterRollRequest(MusterRoll musterRoll) {

//Check if the startDate is Monday - UI sends the epoch time in IST
LocalDate startDate = Instant.ofEpochMilli(musterRoll.getStartDate().longValue()).atZone(ZoneId.of(serviceConfiguration.getTimeZone())).toLocalDate();
if (startDate.getDayOfWeek() != DayOfWeek.MONDAY) {
if (serviceConfiguration.isValidateStartDateMondayEnabled() && startDate.getDayOfWeek() != DayOfWeek.MONDAY) {
throw new CustomException("START_DATE_MONDAY","StartDate should be Monday");
}
musterRoll.setStartDate(new BigDecimal(startDate.atStartOfDay(ZoneId.of(serviceConfiguration.getTimeZone())).toInstant().toEpochMilli()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.egov.web.models.MusterRollRequest;
import org.egov.web.models.MusterRollResponse;
import org.egov.web.models.MusterRollSearchCriteria;
import org.egov.web.models.MusterRollSearchRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
Expand Down Expand Up @@ -58,11 +59,17 @@ public ResponseEntity<MusterRollResponse> musterRollV1CreatePost(@ApiParam(value
}

@RequestMapping(value = "/_search", method = RequestMethod.POST)
public ResponseEntity<MusterRollResponse> attendanceV1SearchPOST(@Valid @RequestBody RequestInfoWrapper requestInfoWrapper, @Valid @ModelAttribute MusterRollSearchCriteria searchCriteria) {
public ResponseEntity<MusterRollResponse> musterRollV1SearchPOST(@Valid @RequestBody RequestInfoWrapper requestInfoWrapper, @Valid @ModelAttribute MusterRollSearchCriteria searchCriteria) {
MusterRollResponse musterRollResponse = musterRollService.searchMusterRolls(requestInfoWrapper, searchCriteria);
return new ResponseEntity<MusterRollResponse>(musterRollResponse, HttpStatus.OK);
}

@RequestMapping(value = "/v2/_search", method = RequestMethod.POST)
public ResponseEntity<MusterRollResponse> musterRollV2SearchPOST(@Valid @RequestBody MusterRollSearchRequest request) {
MusterRollResponse musterRollResponse = musterRollService.searchMusterRolls(request, request.getMusterRoll());
return new ResponseEntity<MusterRollResponse>(musterRollResponse, HttpStatus.OK);
}

@RequestMapping(value = "/_update", method = RequestMethod.POST)
public ResponseEntity<MusterRollResponse> musterRollV1UpdatePost(@ApiParam(value = "Request object to update the muster roll", required = true) @Valid @RequestBody MusterRollRequest body) {
MusterRollRequest musterRollRequest = musterRollService.updateMusterRoll(body);
Expand Down
Loading