diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java index 2cf5d3ca..5693193c 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationAmendmentRequestDao.java @@ -990,7 +990,7 @@ public class ApplicationAmendmentRequestDao { } setIfUpdated(existingApplicationAmendment::getInternalNote, existingApplicationAmendment::setInternalNote, closeAmendmentRequest.getInternalNote()); setIfUpdated(existingApplicationAmendment::getStatus, existingApplicationAmendment::setStatus, ApplicationAmendmentRequestEnum.CLOSE.getValue()); - + existingApplicationAmendment.setClosingDate(LocalDateTime.now()); ApplicationAmendmentRequestEntity updatedApplicationAmendment = saveApplicationAmendmentRequestEntity(existingApplicationAmendment, oldApplicationAmendmentEntity, VersionActionTypeEnum.UPDATE); ApplicationAmendmentRequestResponse response = convertEntityToResponse(updatedApplicationAmendment,false); diff --git a/src/main/java/net/gepafin/tendermanagement/dao/DashboardDao.java b/src/main/java/net/gepafin/tendermanagement/dao/DashboardDao.java index 8f3a55f1..53309e9d 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/DashboardDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/DashboardDao.java @@ -6,15 +6,14 @@ import net.gepafin.tendermanagement.entities.UserActionEntity; import net.gepafin.tendermanagement.entities.UserEntity; import net.gepafin.tendermanagement.entities.UserWithCompanyEntity; import net.gepafin.tendermanagement.entities.*; +import net.gepafin.tendermanagement.enums.ApplicationAmendmentRequestEnum; import net.gepafin.tendermanagement.enums.CallStatusEnum; import net.gepafin.tendermanagement.enums.RoleStatusEnum; import net.gepafin.tendermanagement.enums.UserStatusEnum; -import net.gepafin.tendermanagement.model.response.ApplicationWidgetResponseBean; -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.model.response.*; import net.gepafin.tendermanagement.repositories.*; import net.gepafin.tendermanagement.service.CompanyService; +import net.gepafin.tendermanagement.util.Validator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -22,6 +21,8 @@ import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Component; import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.temporal.ChronoUnit; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -58,6 +59,13 @@ public class DashboardDao { @Autowired private UserActionsRepository userActionsRepository; + @Autowired + private ApplicationAmendmentRequestRepository applicationAmendmentRequestRepository; + + @Autowired + private AssignedApplicationsRepository assignedApplicationsRepository; + @Autowired + private Validator validator; public SuperAdminWidgetResponseBean getDashboardWidget(UserEntity requestedUserEntity) { SuperAdminWidgetResponseBean widgetResponseBean = new SuperAdminWidgetResponseBean(); @@ -263,6 +271,95 @@ public class DashboardDao { 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 applicationIds = getApplicationIdsForUserOrHub(userEntity,hubId); + setAmendmentCounts(applicationIds,amendmentWidgetResponseBean, hubId); + calculateExpiringRequestsIn48Hours(applicationIds,amendmentWidgetResponseBean, hubId); + calculateAverageResponseDays(applicationIds,amendmentWidgetResponseBean,hubId); + return amendmentWidgetResponseBean; + } + public List getApplicationIdsForUserOrHub(UserEntity userEntity, Long hubId) { + if (validator.checkIsPreInstructor()) { + return assignedApplicationsRepository.findApplicationIdsByUserIdAndIsDeletedFalse(userEntity.getId()); + } else { + return applicationRepository.findApplicationIdsByHubId(hubId); + } + } + + private void setAmendmentCounts(List 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 applicationIds ,AmendmentWidgetResponseBean responseBean, Long hubId) { + + // Define the statuses to filter + List 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 applicationIds ,AmendmentWidgetResponseBean responseBean, Long hubId) { + + if (!applicationIds.isEmpty()) { + BigDecimal averageResponseDays = applicationAmendmentRequestRepository + .findAverageResponseDaysByApplicationIdsAndStatus( + applicationIds, + ApplicationAmendmentRequestEnum.CLOSE.getValue() + ); + + responseBean.setAverageResponseDays(averageResponseDays); + } else { + responseBean.setAverageResponseDays(BigDecimal.ZERO); + } + } } diff --git a/src/main/java/net/gepafin/tendermanagement/entities/ApplicationAmendmentRequestEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationAmendmentRequestEntity.java index 8a8701a1..840ad050 100644 --- a/src/main/java/net/gepafin/tendermanagement/entities/ApplicationAmendmentRequestEntity.java +++ b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationAmendmentRequestEntity.java @@ -53,4 +53,7 @@ public class ApplicationAmendmentRequestEntity extends BaseEntity { @Column(name = "amendment_document") private String amendmentDocument; + + @Column(name = "CLOSING_DATE") + private LocalDateTime closingDate; } diff --git a/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java index 5cae2da0..64fd530c 100644 --- a/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java +++ b/src/main/java/net/gepafin/tendermanagement/enums/UserActionContextEnum.java @@ -137,6 +137,7 @@ public enum UserActionContextEnum { GET_DASHBOARD_WIDGET_FOR_SUPER_ADMIN("GET_DASHBOARD_WIDGET_FOR_SUPER_ADMIN"), GET_DASHBOARD_WIDGET_FOR_BENEFICIARY("GET_DASHBOARD_WIDGET_FOR_BENEFICIARY"), GET_APPLICATION_DETAILS("GET_APPLICATION_DETAILS"), + GET_AMENDMENT_DETAILS("GET_AMENDMENT_DETAILS"), /** Evaluation criteria action context **/ GET_EVALUATION_CRITERIA("GET_EVALUATION_CRITERIA"), diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/AmendmentWidgetResponseBean.java b/src/main/java/net/gepafin/tendermanagement/model/response/AmendmentWidgetResponseBean.java new file mode 100644 index 00000000..365ecbf0 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/model/response/AmendmentWidgetResponseBean.java @@ -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; +} diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationAmendmentRequestRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationAmendmentRequestRepository.java index 3c89993c..89bd8098 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationAmendmentRequestRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationAmendmentRequestRepository.java @@ -9,6 +9,8 @@ import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import java.math.BigDecimal; +import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; import java.util.Optional; @@ -80,4 +82,54 @@ public interface ApplicationAmendmentRequestRepository extends JpaRepository 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 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 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 findAllByApplicationIdsAndStatuses( + @Param("applicationIds") List applicationIds, + @Param("statuses") List statuses + ); + List findAllByApplicationIdInAndStatusAndIsDeletedFalse(List 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 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 applicationIds, + @Param("statuses") List statuses, + @Param("startDate") LocalDateTime startDate, + @Param("endDate") LocalDateTime endDate + ); } diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/AssignedApplicationsRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/AssignedApplicationsRepository.java index dac54c98..56036759 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/AssignedApplicationsRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/AssignedApplicationsRepository.java @@ -22,4 +22,7 @@ public interface AssignedApplicationsRepository extends JpaRepository 'CLOSE'") Long countAssignedApplicationsByUserId(@Param("userId") Long userId); + + @Query("SELECT aa.application.id FROM AssignedApplicationsEntity aa WHERE aa.isDeleted = false AND aa.userId = :userId") + List findApplicationIdsByUserIdAndIsDeletedFalse(@Param("userId") Long userId); } diff --git a/src/main/java/net/gepafin/tendermanagement/service/DashboardService.java b/src/main/java/net/gepafin/tendermanagement/service/DashboardService.java index 0e34c1b6..ee7429d4 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/DashboardService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/DashboardService.java @@ -1,6 +1,7 @@ package net.gepafin.tendermanagement.service; 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.BeneficiaryWidgetResponseBean; import net.gepafin.tendermanagement.model.response.SuperAdminWidgetResponseBean; @@ -11,4 +12,5 @@ public interface DashboardService { public BeneficiaryWidgetResponseBean getDashboardWidgetForBeneficiary(HttpServletRequest request, Long companyId); public ApplicationWidgetResponseBean getApplicationDetails(HttpServletRequest request); + public AmendmentWidgetResponseBean getAmendmentDetails(HttpServletRequest request); } diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/DashboardServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/DashboardServiceImpl.java index e578a3dc..e157d293 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/DashboardServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/DashboardServiceImpl.java @@ -4,6 +4,7 @@ import jakarta.servlet.http.HttpServletRequest; import net.gepafin.tendermanagement.dao.DashboardDao; import net.gepafin.tendermanagement.entities.CompanyEntity; 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.BeneficiaryWidgetResponseBean; import net.gepafin.tendermanagement.model.response.SuperAdminWidgetResponseBean; @@ -39,4 +40,9 @@ public class DashboardServiceImpl implements DashboardService { UserEntity userEntity=validator.validateUser(request); return dashboardDao.getApplicationDetails(userEntity); } + @Override + public AmendmentWidgetResponseBean getAmendmentDetails(HttpServletRequest request) { + UserEntity userEntity=validator.validateUser(request); + return dashboardDao.getAmendmentDetails(userEntity); + } } diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/DashboardApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/DashboardApi.java index 31ae1be3..bf1779fc 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/DashboardApi.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/DashboardApi.java @@ -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.responses.ApiResponse; 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.BeneficiaryWidgetResponseBean; import net.gepafin.tendermanagement.model.response.SuperAdminWidgetResponseBean; @@ -61,5 +62,17 @@ public interface DashboardApi { produces = { "application/json" }) @PreAuthorize("hasRole('ROLE_SUPER_ADMIN') || hasRole('ROLE_INSTRUCTOR_MANAGER')") ResponseEntity> 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> getAmendmentDetails(HttpServletRequest request); } diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/DashboardApiController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/DashboardApiController.java index ed1f3d68..c9bc0d85 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/DashboardApiController.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/DashboardApiController.java @@ -6,6 +6,7 @@ import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.enums.UserActionContextEnum; import net.gepafin.tendermanagement.enums.UserActionLogsEnum; 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.BeneficiaryWidgetResponseBean; import net.gepafin.tendermanagement.model.response.SuperAdminWidgetResponseBean; @@ -60,4 +61,14 @@ public class DashboardApiController implements DashboardApi { return ResponseEntity.status(HttpStatus.CREATED) .body(new Response<>(widgetResponseBean, Status.SUCCESS, Translator.toLocale(GepafinConstant.DASHBOARD_WIDGET_FETCHED_SUCCESSFULLY))); } + @Override + public ResponseEntity> 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))); + } } diff --git a/src/main/resources/db/changelog/db.changelog-1.0.0.xml b/src/main/resources/db/changelog/db.changelog-1.0.0.xml index d8c7dbea..bf3fd60b 100644 --- a/src/main/resources/db/changelog/db.changelog-1.0.0.xml +++ b/src/main/resources/db/changelog/db.changelog-1.0.0.xml @@ -2229,4 +2229,11 @@ + + + + + + +