Merge pull request #171 from Kitzanos/feature/GEPAFINBE-141

GEPAFINBE-141 (Instructor: summary stats for soccorso page)
This commit is contained in:
Rinaldo
2025-01-21 10:16:09 +01:00
committed by GitHub
12 changed files with 222 additions and 6 deletions

View File

@@ -990,7 +990,7 @@ public class ApplicationAmendmentRequestDao {
} }
setIfUpdated(existingApplicationAmendment::getInternalNote, existingApplicationAmendment::setInternalNote, closeAmendmentRequest.getInternalNote()); setIfUpdated(existingApplicationAmendment::getInternalNote, existingApplicationAmendment::setInternalNote, closeAmendmentRequest.getInternalNote());
setIfUpdated(existingApplicationAmendment::getStatus, existingApplicationAmendment::setStatus, ApplicationAmendmentRequestEnum.CLOSE.getValue()); setIfUpdated(existingApplicationAmendment::getStatus, existingApplicationAmendment::setStatus, ApplicationAmendmentRequestEnum.CLOSE.getValue());
existingApplicationAmendment.setClosingDate(LocalDateTime.now());
ApplicationAmendmentRequestEntity updatedApplicationAmendment = saveApplicationAmendmentRequestEntity(existingApplicationAmendment, oldApplicationAmendmentEntity, ApplicationAmendmentRequestEntity updatedApplicationAmendment = saveApplicationAmendmentRequestEntity(existingApplicationAmendment, oldApplicationAmendmentEntity,
VersionActionTypeEnum.UPDATE); VersionActionTypeEnum.UPDATE);
ApplicationAmendmentRequestResponse response = convertEntityToResponse(updatedApplicationAmendment,false); ApplicationAmendmentRequestResponse response = convertEntityToResponse(updatedApplicationAmendment,false);

View File

@@ -6,15 +6,14 @@ import net.gepafin.tendermanagement.entities.UserActionEntity;
import net.gepafin.tendermanagement.entities.UserEntity; import net.gepafin.tendermanagement.entities.UserEntity;
import net.gepafin.tendermanagement.entities.UserWithCompanyEntity; import net.gepafin.tendermanagement.entities.UserWithCompanyEntity;
import net.gepafin.tendermanagement.entities.*; import net.gepafin.tendermanagement.entities.*;
import net.gepafin.tendermanagement.enums.ApplicationAmendmentRequestEnum;
import net.gepafin.tendermanagement.enums.CallStatusEnum; import net.gepafin.tendermanagement.enums.CallStatusEnum;
import net.gepafin.tendermanagement.enums.RoleStatusEnum; import net.gepafin.tendermanagement.enums.RoleStatusEnum;
import net.gepafin.tendermanagement.enums.UserStatusEnum; import net.gepafin.tendermanagement.enums.UserStatusEnum;
import net.gepafin.tendermanagement.model.response.ApplicationWidgetResponseBean; import net.gepafin.tendermanagement.model.response.*;
import net.gepafin.tendermanagement.model.response.BeneficiaryWidgetResponseBean;
import net.gepafin.tendermanagement.model.response.Widget1;
import net.gepafin.tendermanagement.model.response.SuperAdminWidgetResponseBean;
import net.gepafin.tendermanagement.repositories.*; import net.gepafin.tendermanagement.repositories.*;
import net.gepafin.tendermanagement.service.CompanyService; import net.gepafin.tendermanagement.service.CompanyService;
import net.gepafin.tendermanagement.util.Validator;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
@@ -22,6 +21,8 @@ import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.temporal.ChronoUnit;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -58,6 +59,13 @@ public class DashboardDao {
@Autowired @Autowired
private UserActionsRepository userActionsRepository; private UserActionsRepository userActionsRepository;
@Autowired
private ApplicationAmendmentRequestRepository applicationAmendmentRequestRepository;
@Autowired
private AssignedApplicationsRepository assignedApplicationsRepository;
@Autowired
private Validator validator;
public SuperAdminWidgetResponseBean getDashboardWidget(UserEntity requestedUserEntity) { public SuperAdminWidgetResponseBean getDashboardWidget(UserEntity requestedUserEntity) {
SuperAdminWidgetResponseBean widgetResponseBean = new SuperAdminWidgetResponseBean(); SuperAdminWidgetResponseBean widgetResponseBean = new SuperAdminWidgetResponseBean();
@@ -264,6 +272,95 @@ public class DashboardDao {
responseBean.setNumberOfDueApplication(dueApplications); responseBean.setNumberOfDueApplication(dueApplications);
} }
} }
private AmendmentWidgetResponseBean initializeAmendmentResponseBean() {
return AmendmentWidgetResponseBean.builder()
.totalAmendments(0L)
.waitingForResponseAmendments(0L)
.responseReceivedAmendments(0L)
.averageResponseDays(BigDecimal.ZERO)
.expiringRequestsIn48Hours(0L)
.expiredAmendments(0L)
.build();
}
public AmendmentWidgetResponseBean getAmendmentDetails(UserEntity userEntity) {
AmendmentWidgetResponseBean amendmentWidgetResponseBean = initializeAmendmentResponseBean();
Long hubId = userEntity.getHub().getId();
List<Long> applicationIds = getApplicationIdsForUserOrHub(userEntity,hubId);
setAmendmentCounts(applicationIds,amendmentWidgetResponseBean, hubId);
calculateExpiringRequestsIn48Hours(applicationIds,amendmentWidgetResponseBean, hubId);
calculateAverageResponseDays(applicationIds,amendmentWidgetResponseBean,hubId);
return amendmentWidgetResponseBean;
}
public List<Long> getApplicationIdsForUserOrHub(UserEntity userEntity, Long hubId) {
if (validator.checkIsPreInstructor()) {
return assignedApplicationsRepository.findApplicationIdsByUserIdAndIsDeletedFalse(userEntity.getId());
} else {
return applicationRepository.findApplicationIdsByHubId(hubId);
}
}
private void setAmendmentCounts(List<Long> applicationIds,AmendmentWidgetResponseBean responseBean, Long hubId) {
Long totalAmendment = applicationAmendmentRequestRepository.countAmendmentsByApplicationIds(applicationIds);
if (totalAmendment != null) {
responseBean.setTotalAmendments(totalAmendment);
}
Long awaitingAmendments = applicationAmendmentRequestRepository.countAmendmentsByApplicationIdsAndStatus(
applicationIds, ApplicationAmendmentRequestEnum.AWAITING.getValue());
if (awaitingAmendments != null) {
responseBean.setWaitingForResponseAmendments(awaitingAmendments);
}
Long responseRecievedAmendments = applicationAmendmentRequestRepository.countAmendmentsByApplicationIdsAndStatus(
applicationIds, ApplicationAmendmentRequestEnum.RESPONSE_RECEIVED.getValue());
if (responseRecievedAmendments != null) {
responseBean.setResponseReceivedAmendments(responseRecievedAmendments);
}
Long expiredAmendments = applicationAmendmentRequestRepository.countAmendmentsByApplicationIdsAndStatus(
applicationIds, ApplicationAmendmentRequestEnum.EXPIRED.getValue());
if (expiredAmendments != null) {
responseBean.setExpiredAmendments(expiredAmendments);
}
}
private void calculateExpiringRequestsIn48Hours(List<Long> applicationIds ,AmendmentWidgetResponseBean responseBean, Long hubId) {
// Define the statuses to filter
List<String> statuses = List.of(
ApplicationAmendmentRequestEnum.AWAITING.getValue(),
ApplicationAmendmentRequestEnum.RESPONSE_RECEIVED.getValue()
);
LocalDateTime twoDaysLater = LocalDateTime.now().plusDays(2);
Long expiringRequestsIn48Hours = applicationAmendmentRequestRepository.countExpiringRequestsIn48Hours(
applicationIds,
statuses,
LocalDateTime.now(),
twoDaysLater
);
if (expiringRequestsIn48Hours != null) {
responseBean.setExpiringRequestsIn48Hours(expiringRequestsIn48Hours);
}
}
private void calculateAverageResponseDays(List<Long> applicationIds ,AmendmentWidgetResponseBean responseBean, Long hubId) {
if (!applicationIds.isEmpty()) {
BigDecimal averageResponseDays = applicationAmendmentRequestRepository
.findAverageResponseDaysByApplicationIdsAndStatus(
applicationIds,
ApplicationAmendmentRequestEnum.CLOSE.getValue()
);
responseBean.setAverageResponseDays(averageResponseDays);
} else {
responseBean.setAverageResponseDays(BigDecimal.ZERO);
}
}
} }

View File

@@ -53,4 +53,7 @@ public class ApplicationAmendmentRequestEntity extends BaseEntity {
@Column(name = "amendment_document") @Column(name = "amendment_document")
private String amendmentDocument; private String amendmentDocument;
@Column(name = "CLOSING_DATE")
private LocalDateTime closingDate;
} }

View File

@@ -137,6 +137,7 @@ public enum UserActionContextEnum {
GET_DASHBOARD_WIDGET_FOR_SUPER_ADMIN("GET_DASHBOARD_WIDGET_FOR_SUPER_ADMIN"), GET_DASHBOARD_WIDGET_FOR_SUPER_ADMIN("GET_DASHBOARD_WIDGET_FOR_SUPER_ADMIN"),
GET_DASHBOARD_WIDGET_FOR_BENEFICIARY("GET_DASHBOARD_WIDGET_FOR_BENEFICIARY"), GET_DASHBOARD_WIDGET_FOR_BENEFICIARY("GET_DASHBOARD_WIDGET_FOR_BENEFICIARY"),
GET_APPLICATION_DETAILS("GET_APPLICATION_DETAILS"), GET_APPLICATION_DETAILS("GET_APPLICATION_DETAILS"),
GET_AMENDMENT_DETAILS("GET_AMENDMENT_DETAILS"),
/** Evaluation criteria action context **/ /** Evaluation criteria action context **/
GET_EVALUATION_CRITERIA("GET_EVALUATION_CRITERIA"), GET_EVALUATION_CRITERIA("GET_EVALUATION_CRITERIA"),

View File

@@ -0,0 +1,22 @@
package net.gepafin.tendermanagement.model.response;
import lombok.Builder;
import lombok.Data;
import java.math.BigDecimal;
@Builder
@Data
public class AmendmentWidgetResponseBean {
private Long totalAmendments;
private Long waitingForResponseAmendments;
private Long responseReceivedAmendments;
private BigDecimal averageResponseDays;
private Long expiringRequestsIn48Hours;
private Long expiredAmendments;
}

View File

@@ -9,6 +9,8 @@ import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Param;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@@ -80,4 +82,54 @@ public interface ApplicationAmendmentRequestRepository extends JpaRepository<App
"AND a.endDate BETWEEN :startTime AND :endTime") "AND a.endDate BETWEEN :startTime AND :endTime")
List<ApplicationAmendmentRequestEntity> findExpiringBetween(LocalDateTime startTime, LocalDateTime endTime); List<ApplicationAmendmentRequestEntity> findExpiringBetween(LocalDateTime startTime, LocalDateTime endTime);
@Query("SELECT COUNT(a) FROM ApplicationAmendmentRequestEntity a WHERE a.applicationId IN :applicationIds AND a.isDeleted = false")
Long countAmendmentsByApplicationIds(@Param("applicationIds") List<Long> applicationIds);
@Query("SELECT COUNT(a) FROM ApplicationAmendmentRequestEntity a WHERE a.applicationId IN :applicationIds AND a.status = :status AND a.isDeleted = false")
Long countAmendmentsByApplicationIdsAndStatus(@Param("applicationIds") List<Long> applicationIds, @Param("status") String status);
@Query("""
SELECT e
FROM ApplicationAmendmentRequestEntity e
WHERE e.applicationId IN :applicationIds
AND e.status IN :statuses
AND e.isDeleted = false
""")
List<ApplicationAmendmentRequestEntity> findAllByApplicationIdsAndStatuses(
@Param("applicationIds") List<Long> applicationIds,
@Param("statuses") List<String> statuses
);
List<ApplicationAmendmentRequestEntity> findAllByApplicationIdInAndStatusAndIsDeletedFalse(List<Long> applicationIds, String status);
@Query("""
SELECT COALESCE(AVG(TIMESTAMPDIFF(DAY, a.startDate, a.closingDate)), 0)
FROM ApplicationAmendmentRequestEntity a
WHERE a.applicationId IN :applicationIds
AND a.status = :status
AND a.isDeleted = false
AND a.closingDate IS NOT NULL
""")
BigDecimal findAverageResponseDaysByApplicationIdsAndStatus(
@Param("applicationIds") List<Long> applicationIds,
@Param("status") String status
);
@Query(value = """
SELECT COUNT(*)
FROM application_amendment_request e
WHERE e.application_id IN :applicationIds
AND e.status IN :statuses
AND e.start_date + INTERVAL '1 DAY' * e.response_days <= :endDate
AND e.start_date + INTERVAL '1 DAY' * e.response_days >= :startDate
AND e.is_deleted = false
""", nativeQuery = true)
Long countExpiringRequestsIn48Hours(
@Param("applicationIds") List<Long> applicationIds,
@Param("statuses") List<String> statuses,
@Param("startDate") LocalDateTime startDate,
@Param("endDate") LocalDateTime endDate
);
} }

View File

@@ -22,4 +22,7 @@ public interface AssignedApplicationsRepository extends JpaRepository<AssignedAp
@Query("SELECT COUNT(aa) FROM AssignedApplicationsEntity aa WHERE aa.isDeleted = false AND aa.userId = :userId AND aa.status <> 'CLOSE'") @Query("SELECT COUNT(aa) FROM AssignedApplicationsEntity aa WHERE aa.isDeleted = false AND aa.userId = :userId AND aa.status <> 'CLOSE'")
Long countAssignedApplicationsByUserId(@Param("userId") Long userId); Long countAssignedApplicationsByUserId(@Param("userId") Long userId);
@Query("SELECT aa.application.id FROM AssignedApplicationsEntity aa WHERE aa.isDeleted = false AND aa.userId = :userId")
List<Long> findApplicationIdsByUserIdAndIsDeletedFalse(@Param("userId") Long userId);
} }

View File

@@ -1,6 +1,7 @@
package net.gepafin.tendermanagement.service; package net.gepafin.tendermanagement.service;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import net.gepafin.tendermanagement.model.response.AmendmentWidgetResponseBean;
import net.gepafin.tendermanagement.model.response.ApplicationWidgetResponseBean; import net.gepafin.tendermanagement.model.response.ApplicationWidgetResponseBean;
import net.gepafin.tendermanagement.model.response.BeneficiaryWidgetResponseBean; import net.gepafin.tendermanagement.model.response.BeneficiaryWidgetResponseBean;
import net.gepafin.tendermanagement.model.response.SuperAdminWidgetResponseBean; import net.gepafin.tendermanagement.model.response.SuperAdminWidgetResponseBean;
@@ -11,4 +12,5 @@ public interface DashboardService {
public BeneficiaryWidgetResponseBean getDashboardWidgetForBeneficiary(HttpServletRequest request, Long companyId); public BeneficiaryWidgetResponseBean getDashboardWidgetForBeneficiary(HttpServletRequest request, Long companyId);
public ApplicationWidgetResponseBean getApplicationDetails(HttpServletRequest request); public ApplicationWidgetResponseBean getApplicationDetails(HttpServletRequest request);
public AmendmentWidgetResponseBean getAmendmentDetails(HttpServletRequest request);
} }

View File

@@ -4,6 +4,7 @@ import jakarta.servlet.http.HttpServletRequest;
import net.gepafin.tendermanagement.dao.DashboardDao; import net.gepafin.tendermanagement.dao.DashboardDao;
import net.gepafin.tendermanagement.entities.CompanyEntity; import net.gepafin.tendermanagement.entities.CompanyEntity;
import net.gepafin.tendermanagement.entities.UserEntity; import net.gepafin.tendermanagement.entities.UserEntity;
import net.gepafin.tendermanagement.model.response.AmendmentWidgetResponseBean;
import net.gepafin.tendermanagement.model.response.ApplicationWidgetResponseBean; import net.gepafin.tendermanagement.model.response.ApplicationWidgetResponseBean;
import net.gepafin.tendermanagement.model.response.BeneficiaryWidgetResponseBean; import net.gepafin.tendermanagement.model.response.BeneficiaryWidgetResponseBean;
import net.gepafin.tendermanagement.model.response.SuperAdminWidgetResponseBean; import net.gepafin.tendermanagement.model.response.SuperAdminWidgetResponseBean;
@@ -39,4 +40,9 @@ public class DashboardServiceImpl implements DashboardService {
UserEntity userEntity=validator.validateUser(request); UserEntity userEntity=validator.validateUser(request);
return dashboardDao.getApplicationDetails(userEntity); return dashboardDao.getApplicationDetails(userEntity);
} }
@Override
public AmendmentWidgetResponseBean getAmendmentDetails(HttpServletRequest request) {
UserEntity userEntity=validator.validateUser(request);
return dashboardDao.getAmendmentDetails(userEntity);
}
} }

View File

@@ -6,6 +6,7 @@ import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject; import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import net.gepafin.tendermanagement.model.response.AmendmentWidgetResponseBean;
import net.gepafin.tendermanagement.model.response.ApplicationWidgetResponseBean; import net.gepafin.tendermanagement.model.response.ApplicationWidgetResponseBean;
import net.gepafin.tendermanagement.model.response.BeneficiaryWidgetResponseBean; import net.gepafin.tendermanagement.model.response.BeneficiaryWidgetResponseBean;
import net.gepafin.tendermanagement.model.response.SuperAdminWidgetResponseBean; import net.gepafin.tendermanagement.model.response.SuperAdminWidgetResponseBean;
@@ -61,5 +62,17 @@ public interface DashboardApi {
produces = { "application/json" }) produces = { "application/json" })
@PreAuthorize("hasRole('ROLE_SUPER_ADMIN') || hasRole('ROLE_INSTRUCTOR_MANAGER')") @PreAuthorize("hasRole('ROLE_SUPER_ADMIN') || hasRole('ROLE_INSTRUCTOR_MANAGER')")
ResponseEntity<Response<ApplicationWidgetResponseBean>> getApplicationDetails(HttpServletRequest request); ResponseEntity<Response<ApplicationWidgetResponseBean>> getApplicationDetails(HttpServletRequest request);
@Operation(summary = "Api to get Soccorso details",
responses = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "404", description = "Not Found", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
@ExampleObject(value = ErrorConstants.NOTFOUND_ERROR_EXAMPLE) })),
@ApiResponse(responseCode = "401", description = "Unauthorized", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
@ExampleObject(value = ErrorConstants.UNAUTHORIZED_ERROR_EXAMPLE) })),
@ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
@ExampleObject(value = ErrorConstants.BADREQUEST_ERROR_EXAMPLE) })) })
@GetMapping(value = "/amendment",
produces = { "application/json" })
@PreAuthorize("hasRole('ROLE_SUPER_ADMIN') || hasRole('ROLE_INSTRUCTOR_MANAGER')|| hasRole('ROLE_PRE_INSTRUCTOR')")
ResponseEntity<Response<AmendmentWidgetResponseBean>> getAmendmentDetails(HttpServletRequest request);
} }

View File

@@ -6,6 +6,7 @@ import net.gepafin.tendermanagement.constants.GepafinConstant;
import net.gepafin.tendermanagement.enums.UserActionContextEnum; import net.gepafin.tendermanagement.enums.UserActionContextEnum;
import net.gepafin.tendermanagement.enums.UserActionLogsEnum; import net.gepafin.tendermanagement.enums.UserActionLogsEnum;
import net.gepafin.tendermanagement.model.request.UserActionRequest; import net.gepafin.tendermanagement.model.request.UserActionRequest;
import net.gepafin.tendermanagement.model.response.AmendmentWidgetResponseBean;
import net.gepafin.tendermanagement.model.response.ApplicationWidgetResponseBean; import net.gepafin.tendermanagement.model.response.ApplicationWidgetResponseBean;
import net.gepafin.tendermanagement.model.response.BeneficiaryWidgetResponseBean; import net.gepafin.tendermanagement.model.response.BeneficiaryWidgetResponseBean;
import net.gepafin.tendermanagement.model.response.SuperAdminWidgetResponseBean; import net.gepafin.tendermanagement.model.response.SuperAdminWidgetResponseBean;
@@ -60,4 +61,14 @@ public class DashboardApiController implements DashboardApi {
return ResponseEntity.status(HttpStatus.CREATED) return ResponseEntity.status(HttpStatus.CREATED)
.body(new Response<>(widgetResponseBean, Status.SUCCESS, Translator.toLocale(GepafinConstant.DASHBOARD_WIDGET_FETCHED_SUCCESSFULLY))); .body(new Response<>(widgetResponseBean, Status.SUCCESS, Translator.toLocale(GepafinConstant.DASHBOARD_WIDGET_FETCHED_SUCCESSFULLY)));
} }
@Override
public ResponseEntity<Response<AmendmentWidgetResponseBean>> getAmendmentDetails(HttpServletRequest request) {
/** This code is responsible for creating user action logs for the "Get dashboard widget for amendment page" operation. **/
loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.VIEW).actionContext(UserActionContextEnum.GET_AMENDMENT_DETAILS).build());
AmendmentWidgetResponseBean widgetResponseBean= dashboardService.getAmendmentDetails(request);
return ResponseEntity.status(HttpStatus.CREATED)
.body(new Response<>(widgetResponseBean, Status.SUCCESS, Translator.toLocale(GepafinConstant.DASHBOARD_WIDGET_FETCHED_SUCCESSFULLY)));
}
} }

View File

@@ -2230,6 +2230,12 @@
</addColumn> </addColumn>
</changeSet> </changeSet>
<changeSet id="21-01-2025_PK_142210" author="Piyush Kag">
<addColumn tableName="application_amendment_request">
<column name="CLOSING_DATE" type="TIMESTAMP WITHOUT TIME ZONE"></column>
</addColumn>
</changeSet>
<changeSet id="16-01-2025_RK_173515" author="Rajesh Khore"> <changeSet id="16-01-2025_RK_173515" author="Rajesh Khore">
<addColumn tableName="hub"> <addColumn tableName="hub">
<column name="evaluation_expiration_days" type="INTEGER"/> <column name="evaluation_expiration_days" type="INTEGER"/>