diff --git a/chpl/chpl-api/src/main/java/gov/healthit/chpl/web/controller/ReportDataController.java b/chpl/chpl-api/src/main/java/gov/healthit/chpl/web/controller/ReportDataController.java index d7c5a6d723..78c09fd1d1 100644 --- a/chpl/chpl-api/src/main/java/gov/healthit/chpl/web/controller/ReportDataController.java +++ b/chpl/chpl-api/src/main/java/gov/healthit/chpl/web/controller/ReportDataController.java @@ -21,6 +21,7 @@ import gov.healthit.chpl.report.surveillance.CapCounts; import gov.healthit.chpl.report.surveillance.NonconformityCounts; import gov.healthit.chpl.report.surveillance.SurveillanceActivityCounts; +import gov.healthit.chpl.report.surveillance.SurveillanceByDeveloper; import gov.healthit.chpl.scheduler.job.summarystatistics.data.CertificationBodyStatistic; import gov.healthit.chpl.search.domain.ListingSearchResult; import gov.healthit.chpl.util.LogMethodUsage; @@ -59,6 +60,17 @@ public ReportDataController(ReportDataManager reportDataManager, return reportDataManager.getHti1CriteriaMigrationReport(); } + @Operation(summary = "Retrieves the data about each surveillance including the related developer.", + description = "Retrieves the data about each surveillance including the related developer.", + security = { + @SecurityRequirement(name = SwaggerSecurityRequirement.API_KEY) + }) + @LogMethodUsage + @RequestMapping(value = "/surveillance-by-developer", method = RequestMethod.GET, produces = "application/json; charset=utf-8") + public @ResponseBody List getSurveillanceOpenDuringTheLastYearForActiveDevelopers() { + return reportDataManager.getSurveillanceOpenDuringTheLastYearForActiveDevelopers(); + } + @Operation(summary = "Retrieves the data used to generate the Surveillance Activity Counts report.", description = "Retrieves the data used to generate the Surveillance Activity Counts report.", security = { diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/compliance/surveillance/SurveillanceDAO.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/compliance/surveillance/SurveillanceDAO.java index 0b54d0d0df..0d1ea0d1d6 100644 --- a/chpl/chpl-service/src/main/java/gov/healthit/chpl/compliance/surveillance/SurveillanceDAO.java +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/compliance/surveillance/SurveillanceDAO.java @@ -6,6 +6,8 @@ import java.util.Set; import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Repository; @@ -27,8 +29,11 @@ import gov.healthit.chpl.domain.surveillance.SurveillanceRequirement; import gov.healthit.chpl.domain.surveillance.SurveillanceResultType; import gov.healthit.chpl.domain.surveillance.SurveillanceType; +import gov.healthit.chpl.entity.developer.DeveloperSearchResultEntity; import gov.healthit.chpl.exception.EntityRetrievalException; import gov.healthit.chpl.exception.UserPermissionRetrievalException; +import gov.healthit.chpl.report.surveillance.SurveillanceByDeveloper; +import gov.healthit.chpl.search.entity.ListingSearchEntity; import gov.healthit.chpl.util.NullSafeEvaluator; import jakarta.persistence.Query; import lombok.extern.log4j.Log4j2; @@ -47,6 +52,17 @@ public class SurveillanceDAO extends BaseDAOImpl { + "LEFT OUTER JOIN FETCH ncs.type nct " + "WHERE surv.deleted <> true "; + private String unformattedListingDetailsUrl; + private String unformattedDeveloperDetailsUrl; + + @Autowired + public SurveillanceDAO(@Value("${chplUrlBegin}") String chplUrlBegin, + @Value("${developerUrlPart}") String developerUrlPart, + @Value("${listingDetailsUrlPart}") String listingDetailsUrlPart) { + this.unformattedDeveloperDetailsUrl = chplUrlBegin + developerUrlPart; + this.unformattedListingDetailsUrl = chplUrlBegin + listingDetailsUrlPart; + } + public Long insertSurveillance(Long certifiedProductId, Surveillance surv) throws UserPermissionRetrievalException { SurveillanceEntity toInsert = new SurveillanceEntity(); populateSurveillanceEntity(certifiedProductId, toInsert, surv); @@ -268,7 +284,6 @@ public Long updateSurveillance(Long certifiedProductId, Surveillance updatedSurv return updatedSurveillance.getId(); } - public SurveillanceEntity getSurveillanceByCertifiedProductAndFriendlyId(Long certifiedProductId, String survFriendlyId) { Query query = entityManager.createQuery( @@ -287,7 +302,6 @@ public SurveillanceEntity getSurveillanceByCertifiedProductAndFriendlyId(Long ce return null; } - public SurveillanceEntity getSurveillanceById(Long id) throws EntityRetrievalException { SurveillanceEntity result = fetchSurveillanceById(id); return result; @@ -310,23 +324,6 @@ public SurveillanceEntity getSurveillanceByNonconformityId(Long nonconformityId) } } - public SurveillanceEntity getSurveillanceByDocumentId(Long documentId) - throws EntityRetrievalException { - entityManager.clear(); - Query query = entityManager.createQuery(SURVEILLANCE_FULL_HQL - + "AND docs.id = :entityid", - SurveillanceEntity.class); - query.setParameter("entityid", documentId); - - List results = query.getResultList(); - if (results == null || results.size() == 0) { - String msg = msgUtil.getMessage("surveillance.notFound"); - throw new EntityRetrievalException(msg); - } else { - return results.get(0); - } - } - public List getSurveillanceByCertifiedProductId(Long id) { entityManager.clear(); Query query = entityManager.createQuery(SURVEILLANCE_FULL_HQL @@ -338,6 +335,39 @@ public List getSurveillanceByCertifiedProductId(Long id) { return results; } + public List getSurveillanceOpenDuringTheLastYearForActiveDevelopers() { + Query query = entityManager.createQuery("SELECT DISTINCT surv, listing, developer " + + "FROM SurveillanceEntity surv, ListingSearchEntity listing, DeveloperSearchResultEntity developer " + + "WHERE (surv.endDate IS NULL OR surv.endDate >= :oneYearAgo) " + + "AND surv.certifiedProductId = listing.id " + + "AND listing.developerId = developer.id " + + "AND developer.currentActiveListingCount > 0 " + + "AND surv.deleted <> true "); + + List results = new ArrayList(); + List entities = query + .setParameter("oneYearAgo", LocalDate.now().minusYears(1)) + .getResultList(); + for (Object[] entity : entities) { + SurveillanceEntity surveillance = (SurveillanceEntity) entity[0]; + ListingSearchEntity listing = (ListingSearchEntity) entity[1]; + DeveloperSearchResultEntity developer = (DeveloperSearchResultEntity) entity[2]; + results.add(SurveillanceByDeveloper.builder() + .developerId(developer.getId()) + .developerName(developer.getDeveloperName()) + .developerDetailsUrl(String.format(unformattedDeveloperDetailsUrl, developer.getId() + "")) + .developerHasActiveListings(developer.getCurrentActiveListingCount() > 0) + .listingId(listing.getId()) + .chplProductNumber(listing.getChplProductNumber()) + .listingDetailsUrl(String.format(unformattedListingDetailsUrl, listing.getId() + "")) + .surveillanceId(surveillance.getId()) + .surveillanceStartDate(surveillance.getStartDate()) + .surveillanceEndDate(surveillance.getEndDate()) + .build()); + } + return results; + + } public void deleteSurveillance(Surveillance surv) throws EntityRetrievalException { LOGGER.debug("Looking for surveillance with id " + surv.getId() + " to delete."); diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/ReportDataManager.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/ReportDataManager.java index ce0fb4719b..dd60fa3b91 100644 --- a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/ReportDataManager.java +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/ReportDataManager.java @@ -32,6 +32,7 @@ import gov.healthit.chpl.report.surveillance.CapCounts; import gov.healthit.chpl.report.surveillance.NonconformityCounts; import gov.healthit.chpl.report.surveillance.SurveillanceActivityCounts; +import gov.healthit.chpl.report.surveillance.SurveillanceByDeveloper; import gov.healthit.chpl.report.surveillance.SurveillanceReportsService; import gov.healthit.chpl.report.svap.SvapReportService; import gov.healthit.chpl.scheduler.job.summarystatistics.data.CertificationBodyStatistic; @@ -112,6 +113,11 @@ public List getHti1CriteriaMigrationReport( return criteriaMigrationReportService.getHtiReportData(CriteriaMigrationReportService.HTI1_REPORT_ID); } + @Synchronized("lock") + public List getSurveillanceOpenDuringTheLastYearForActiveDevelopers() { + return surveillanceReportsService.getSurveillanceOpenDuringTheLastYearForActiveDevelopers(); + } + @Synchronized("lock") public SurveillanceActivityCounts getSurveillanceActivityCounts() { return surveillanceReportsService.getSurveiilanceActivityCounts(); diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/surveillance/SurveillanceByDeveloper.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/surveillance/SurveillanceByDeveloper.java new file mode 100644 index 0000000000..f5cec0fed3 --- /dev/null +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/surveillance/SurveillanceByDeveloper.java @@ -0,0 +1,32 @@ +package gov.healthit.chpl.report.surveillance; + +import java.time.LocalDate; + +import gov.healthit.chpl.util.LocalDateDeserializer; +import gov.healthit.chpl.util.LocalDateSerializer; +import lombok.Builder; +import lombok.Data; +import tools.jackson.databind.annotation.JsonDeserialize; +import tools.jackson.databind.annotation.JsonSerialize; + +@Data +@Builder +public class SurveillanceByDeveloper { + private Long developerId; + private String developerName; + private String developerDetailsUrl; + private boolean developerHasActiveListings; + private Long listingId; + private String chplProductNumber; + private String listingDetailsUrl; + + private Long surveillanceId; + + @JsonDeserialize(using = LocalDateDeserializer.class) + @JsonSerialize(using = LocalDateSerializer.class) + private LocalDate surveillanceStartDate; + + @JsonDeserialize(using = LocalDateDeserializer.class) + @JsonSerialize(using = LocalDateSerializer.class) + private LocalDate surveillanceEndDate; +} diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/surveillance/SurveillanceReportsService.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/surveillance/SurveillanceReportsService.java index b2c64a1ff0..b56c4e9527 100644 --- a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/surveillance/SurveillanceReportsService.java +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/surveillance/SurveillanceReportsService.java @@ -7,6 +7,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import gov.healthit.chpl.compliance.surveillance.SurveillanceDAO; import gov.healthit.chpl.dao.statistics.SummaryStatisticsDAO; import gov.healthit.chpl.entity.CertificationStatusType; import gov.healthit.chpl.exception.ValidationException; @@ -19,6 +20,7 @@ import gov.healthit.chpl.search.domain.ListingSearchResult; import gov.healthit.chpl.search.domain.NonConformitySearchOptions; import gov.healthit.chpl.search.domain.SearchRequest; +import jakarta.transaction.Transactional; import lombok.extern.log4j.Log4j2; @Log4j2 @@ -26,11 +28,21 @@ public class SurveillanceReportsService extends SummaryStatisticsReportBaseService { private ListingSearchService listingSearchService; + private SurveillanceDAO surveillanceDao; @Autowired - public SurveillanceReportsService(SummaryStatisticsDAO summaryStatisticsDAO, ListingSearchService listingSearchService, CertificationBodyManager certificationBodyManager) { + public SurveillanceReportsService(SummaryStatisticsDAO summaryStatisticsDAO, + ListingSearchService listingSearchService, + CertificationBodyManager certificationBodyManager, + SurveillanceDAO surveillanceDao) { super(summaryStatisticsDAO, certificationBodyManager); this.listingSearchService = listingSearchService; + this.surveillanceDao = surveillanceDao; + } + + @Transactional + public List getSurveillanceOpenDuringTheLastYearForActiveDevelopers() { + return surveillanceDao.getSurveillanceOpenDuringTheLastYearForActiveDevelopers(); } public SurveillanceActivityCounts getSurveiilanceActivityCounts() {