From 47254cc73157a428de90ea6dc3195c7589e0847a Mon Sep 17 00:00:00 2001 From: Katy Ekey Date: Wed, 6 May 2026 14:11:54 -0400 Subject: [PATCH 1/7] feat!: Add RWT report summary endpoint for counts by developer [#OCD-5225] --- .../RealWorldTestingReportController.java | 41 +++-- ...dTestingPlanSummaryByAcbReportEntity.java} | 8 +- ...ingPlanSummaryByDeveloperReportEntity.java | 66 ++++++++ .../RealWorldTestingPlanSummaryReportDao.java | 99 ++++++++++-- .../RealWorldTestingReportDataService.java | 32 +++- ...stingResultsSummaryByAcbReportEntity.java} | 8 +- ...ResultsSummaryByDeveloperReportEntity.java | 66 ++++++++ ...alWorldTestingResultsSummaryReportDao.java | 99 +++++++++--- ...> RealWorldTestingSummaryByAcbReport.java} | 2 +- ...lWorldTestingSummaryByDeveloperReport.java | 27 ++++ ...alWorldTestingSummaryReportCreatorJob.java | 151 ++++++++++++++++-- .../RwtPopulateMissingDataCreatorJob.java | 8 +- 12 files changed, 528 insertions(+), 79 deletions(-) rename chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/{RealWorldTestingPlanSummaryReportEntity.java => RealWorldTestingPlanSummaryByAcbReportEntity.java} (87%) create mode 100644 chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingPlanSummaryByDeveloperReportEntity.java rename chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/{RealWorldTestingResultsSummaryReportEntity.java => RealWorldTestingResultsSummaryByAcbReportEntity.java} (86%) create mode 100644 chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingResultsSummaryByDeveloperReportEntity.java rename chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/{RealWorldTestingSummaryReport.java => RealWorldTestingSummaryByAcbReport.java} (93%) create mode 100644 chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingSummaryByDeveloperReport.java diff --git a/chpl/chpl-api/src/main/java/gov/healthit/chpl/web/controller/RealWorldTestingReportController.java b/chpl/chpl-api/src/main/java/gov/healthit/chpl/web/controller/RealWorldTestingReportController.java index 3698cf54f5..aa7f5b8a99 100644 --- a/chpl/chpl-api/src/main/java/gov/healthit/chpl/web/controller/RealWorldTestingReportController.java +++ b/chpl/chpl-api/src/main/java/gov/healthit/chpl/web/controller/RealWorldTestingReportController.java @@ -9,7 +9,8 @@ import org.springframework.web.bind.annotation.RestController; import gov.healthit.chpl.report.ReportDataManager; -import gov.healthit.chpl.report.realworldtesting.RealWorldTestingSummaryReport; +import gov.healthit.chpl.report.realworldtesting.RealWorldTestingSummaryByAcbReport; +import gov.healthit.chpl.report.realworldtesting.RealWorldTestingSummaryByDeveloperReport; import gov.healthit.chpl.util.LogMethodUsage; import gov.healthit.chpl.util.SwaggerSecurityRequirement; import io.swagger.v3.oas.annotations.Operation; @@ -30,25 +31,47 @@ public RealWorldTestingReportController(ReportDataManager reportDataManager) { this.reportDataManager = reportDataManager; } - @Operation(summary = "Retrieves the data used to generate the Real World Testing Plans report.", - description = "Retrieves the data used to generate the Real World Testing Plans report.", + @Operation(summary = "Retrieves the data used to generate the Real World Testing Plans summary by ACB report.", + description = "Retrieves the data used to generate the Real World Testing Plans summary by ACB report.", security = { @SecurityRequirement(name = SwaggerSecurityRequirement.API_KEY) }) @LogMethodUsage @RequestMapping(value = "/plans", method = RequestMethod.GET, produces = "application/json; charset=utf-8") - public @ResponseBody List getRealWorldTestingPlanReports() { - return reportDataManager.getRealWorldTestingReportDataService().getRealWorldTestingPlanSummaryReports(); + public @ResponseBody List getRealWorldTestingPlanSummaryByAcbReports() { + return reportDataManager.getRealWorldTestingReportDataService().getRealWorldTestingPlanSummaryByAcbReports(); } - @Operation(summary = "Retrieves the data used to generate the Real World Testing Results report.", - description = "Retrieves the data used to generate the Real World Testing Results report.", + @Operation(summary = "Retrieves the data used to generate the Real World Testing Results summary by ACB report.", + description = "Retrieves the data used to generate the Real World Testing Results summary by ACB report.", security = { @SecurityRequirement(name = SwaggerSecurityRequirement.API_KEY) }) @LogMethodUsage @RequestMapping(value = "/results", method = RequestMethod.GET, produces = "application/json; charset=utf-8") - public @ResponseBody List getRealWorldTestingResultsReports() { - return reportDataManager.getRealWorldTestingReportDataService().getRealWorldTestingResultsSummaryReports(); + public @ResponseBody List getRealWorldTestingResultsSummaryByAcbReports() { + return reportDataManager.getRealWorldTestingReportDataService().getRealWorldTestingResultsSummaryByAcbReports(); + } + + @Operation(summary = "Retrieves the data used to generate the Real World Testing Plans summary by Developer report.", + description = "Retrieves the data used to generate the Real World Testing Plans summary by Developer report.", + security = { + @SecurityRequirement(name = SwaggerSecurityRequirement.API_KEY) + }) + @LogMethodUsage + @RequestMapping(value = "/plans-summary-by-developer", method = RequestMethod.GET, produces = "application/json; charset=utf-8") + public @ResponseBody List getRealWorldTestingPlanSummaryByDeveloperReports() { + return reportDataManager.getRealWorldTestingReportDataService().getRealWorldTestingPlanSummaryByDeveloperReports(); + } + + @Operation(summary = "Retrieves the data used to generate the Real World Testing Results summary by Developer report.", + description = "Retrieves the data used to generate the Real World Testing Results summary by Developer report.", + security = { + @SecurityRequirement(name = SwaggerSecurityRequirement.API_KEY) + }) + @LogMethodUsage + @RequestMapping(value = "/results-summary-by-developer", method = RequestMethod.GET, produces = "application/json; charset=utf-8") + public @ResponseBody List getRealWorldTestingResultsSummaryByDeveloperReports() { + return reportDataManager.getRealWorldTestingReportDataService().getRealWorldTestingResultsSummaryByDeveloperReports(); } } diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingPlanSummaryReportEntity.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingPlanSummaryByAcbReportEntity.java similarity index 87% rename from chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingPlanSummaryReportEntity.java rename to chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingPlanSummaryByAcbReportEntity.java index 09313c9a26..c4dff67e49 100644 --- a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingPlanSummaryReportEntity.java +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingPlanSummaryByAcbReportEntity.java @@ -27,8 +27,8 @@ @AllArgsConstructor @NoArgsConstructor @Entity -@Table(name = "real_world_testing_plan_summary_report") -public class RealWorldTestingPlanSummaryReportEntity extends EntityAudit { +@Table(name = "real_world_testing_plan_summary_by_acb_report") +public class RealWorldTestingPlanSummaryByAcbReportEntity extends EntityAudit { private static final long serialVersionUID = -1208758504334058893L; @Id @@ -52,8 +52,8 @@ public class RealWorldTestingPlanSummaryReportEntity extends EntityAudit { @Column(name = "requires_check_count") private Long requiresCheckCount; - public RealWorldTestingSummaryReport toDomain() { - return RealWorldTestingSummaryReport.builder() + public RealWorldTestingSummaryByAcbReport toDomain() { + return RealWorldTestingSummaryByAcbReport.builder() .id(id) .realWorldTestingYear(realWorldTestingYear) .certificationBody(certificationBody.toDomain()) diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingPlanSummaryByDeveloperReportEntity.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingPlanSummaryByDeveloperReportEntity.java new file mode 100644 index 0000000000..861b10e7f3 --- /dev/null +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingPlanSummaryByDeveloperReportEntity.java @@ -0,0 +1,66 @@ +package gov.healthit.chpl.report.realworldtesting; + +import java.time.LocalDate; + +import gov.healthit.chpl.entity.EntityAudit; +import gov.healthit.chpl.entity.developer.DeveloperEntitySimple; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import lombok.experimental.SuperBuilder; + +@Getter +@Setter +@ToString +@SuperBuilder +@AllArgsConstructor +@NoArgsConstructor +@Entity +@Table(name = "real_world_testing_plan_summary_by_developer_report") +public class RealWorldTestingPlanSummaryByDeveloperReportEntity extends EntityAudit { + private static final long serialVersionUID = -1291758504534058893L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Column(name = "real_world_testing_year") + private Long realWorldTestingYear; + + @OneToOne(optional = true, fetch = FetchType.LAZY) + @JoinColumn(name = "developer_id") + private DeveloperEntitySimple developer; + + @Column(name = "checked_date") + private LocalDate checkedDate; + + @Column(name = "checked_count") + private Long checkedCount; + + @Column(name = "requires_check_count") + private Long requiresCheckCount; + + public RealWorldTestingSummaryByDeveloperReport toDomain() { + return RealWorldTestingSummaryByDeveloperReport.builder() + .id(id) + .realWorldTestingYear(realWorldTestingYear) + .developerId(developer != null ? developer.getId() : null) + .developerName(developer != null ? developer.getName() : null) + .checkedDate(checkedDate) + .checkedCount(checkedCount) + .requiresCheckCount(requiresCheckCount) + .build(); + } +} diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingPlanSummaryReportDao.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingPlanSummaryReportDao.java index ad4c1ab6ea..2ea9cf046a 100644 --- a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingPlanSummaryReportDao.java +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingPlanSummaryReportDao.java @@ -8,17 +8,18 @@ import gov.healthit.chpl.dao.impl.BaseDAOImpl; import gov.healthit.chpl.entity.CertificationBodyEntity; +import gov.healthit.chpl.entity.developer.DeveloperEntitySimple; import gov.healthit.chpl.exception.EntityRetrievalException; import jakarta.persistence.Query; @Component public class RealWorldTestingPlanSummaryReportDao extends BaseDAOImpl { - public void save(RealWorldTestingSummaryReport realWorldTestingSummaryReport) throws EntityRetrievalException { - RealWorldTestingPlanSummaryReportEntity entity = getEntityByCheckedDateAndAcb(realWorldTestingSummaryReport.getCheckedDate(), + public void save(RealWorldTestingSummaryByAcbReport realWorldTestingSummaryReport) throws EntityRetrievalException { + RealWorldTestingPlanSummaryByAcbReportEntity entity = getEntityByCheckedDateAndAcb(realWorldTestingSummaryReport.getCheckedDate(), realWorldTestingSummaryReport.getCertificationBody().getId()); if (entity == null) { - entity = RealWorldTestingPlanSummaryReportEntity.builder() + entity = RealWorldTestingPlanSummaryByAcbReportEntity.builder() .realWorldTestingYear(realWorldTestingSummaryReport.getRealWorldTestingYear()) .certificationBody(CertificationBodyEntity.builder() .id(realWorldTestingSummaryReport.getCertificationBody().getId()) @@ -36,33 +37,33 @@ public void save(RealWorldTestingSummaryReport realWorldTestingSummaryReport) th } } - public Optional getMaxRealWorldTestingYear() { + public Optional getMaxRealWorldTestingYearForAcbSummary() { return Optional.ofNullable(entityManager.createQuery( "select MAX(rwtpsr.realWorldTestingYear) " - + "from RealWorldTestingPlanSummaryReportEntity rwtpsr " + + "from RealWorldTestingPlanSummaryByAcbReportEntity rwtpsr " + "where (NOT deleted = true)", Long.class) .getSingleResult()); } - public List getRealWorldTestingReportsByTestingYear(Long realWorldTestingYear) { - return getEntitiesByRealWorldTestingYear(realWorldTestingYear).stream() + public List getRealWorldTestingSummaryByAcbReportsByTestingYear(Long realWorldTestingYear) { + return getAcbSummaryEntitiesByRealWorldTestingYear(realWorldTestingYear).stream() .map(entity -> entity.toDomain()) .toList(); } - private RealWorldTestingPlanSummaryReportEntity getEntityByCheckedDateAndAcb(LocalDate checkedDate, Long certificationBodyId) throws EntityRetrievalException { + private RealWorldTestingPlanSummaryByAcbReportEntity getEntityByCheckedDateAndAcb(LocalDate checkedDate, Long certificationBodyId) throws EntityRetrievalException { Query query = entityManager.createQuery( - "from RealWorldTestingPlanSummaryReportEntity rwtps " + "from RealWorldTestingPlanSummaryByAcbReportEntity rwtps " + "where (NOT deleted = true) " + "and checkedDate = :checkedDate " - + "and rwtps.certificationBody.id = :certificationBodyId", RealWorldTestingPlanSummaryReportEntity.class); + + "and rwtps.certificationBody.id = :certificationBodyId", RealWorldTestingPlanSummaryByAcbReportEntity.class); query.setParameter("checkedDate", checkedDate); query.setParameter("certificationBodyId", certificationBodyId); - List result = query.getResultList(); + List result = query.getResultList(); if (result.size() > 1) { - throw new EntityRetrievalException("Data error. Duplicate checked_date in real_world_testing_plan_summary_report table."); + throw new EntityRetrievalException("Data error. Duplicate checked_date in real_world_testing_plan_summary_by_acb_report table."); } if (result.size() > 0) { @@ -71,11 +72,79 @@ private RealWorldTestingPlanSummaryReportEntity getEntityByCheckedDateAndAcb(Loc return null; } - private List getEntitiesByRealWorldTestingYear(Long testingYear) { + private List getAcbSummaryEntitiesByRealWorldTestingYear(Long testingYear) { return entityManager.createQuery( - "from RealWorldTestingPlanSummaryReportEntity rwtps " + "from RealWorldTestingPlanSummaryByAcbReportEntity rwtps " + "where (NOT deleted = true) " - + "and rwtps.realWorldTestingYear = :realWorldTestingYear", RealWorldTestingPlanSummaryReportEntity.class) + + "and rwtps.realWorldTestingYear = :realWorldTestingYear", RealWorldTestingPlanSummaryByAcbReportEntity.class) + .setParameter("realWorldTestingYear", testingYear) + .getResultList(); + } + + public void save(RealWorldTestingSummaryByDeveloperReport realWorldTestingSummaryReport) throws EntityRetrievalException { + RealWorldTestingPlanSummaryByDeveloperReportEntity entity = getEntityByCheckedDateAndDeveloper(realWorldTestingSummaryReport.getCheckedDate(), + realWorldTestingSummaryReport.getDeveloperId()); + if (entity == null) { + entity = RealWorldTestingPlanSummaryByDeveloperReportEntity.builder() + .realWorldTestingYear(realWorldTestingSummaryReport.getRealWorldTestingYear()) + .developer(DeveloperEntitySimple.builder() + .id(realWorldTestingSummaryReport.getDeveloperId()) + .build()) + .checkedDate(realWorldTestingSummaryReport.getCheckedDate()) + .checkedCount(realWorldTestingSummaryReport.getCheckedCount()) + .requiresCheckCount(realWorldTestingSummaryReport.getRequiresCheckCount()) + .build(); + + create(entity); + } else { + entity.setCheckedCount(realWorldTestingSummaryReport.getCheckedCount()); + entity.setRequiresCheckCount(realWorldTestingSummaryReport.getRequiresCheckCount()); + update(entity); + } + } + + public Optional getMaxRealWorldTestingYearForDeveloperSummary() { + return Optional.ofNullable(entityManager.createQuery( + "select MAX(rwtpsr.realWorldTestingYear) " + + "from RealWorldTestingPlanSummaryByDeveloperReportEntity rwtpsr " + + "where (NOT deleted = true)", Long.class) + .getSingleResult()); + + } + + public List getRealWorldTestingSummaryByDeveloperReportsByTestingYear(Long realWorldTestingYear) { + return getDeveloperSummaryEntitiesByRealWorldTestingYear(realWorldTestingYear).stream() + .map(entity -> entity.toDomain()) + .toList(); + } + + private RealWorldTestingPlanSummaryByDeveloperReportEntity getEntityByCheckedDateAndDeveloper(LocalDate checkedDate, Long developerId) throws EntityRetrievalException { + Query query = entityManager.createQuery( + "from RealWorldTestingPlanSummaryByDeveloperReportEntity rwtps " + + "JOIN FETCH rwtps.developer dev " + + "where (NOT rwtps.deleted = true) " + + "and rwtps.checkedDate = :checkedDate " + + "and dev.id = :developerId", RealWorldTestingPlanSummaryByAcbReportEntity.class); + query.setParameter("checkedDate", checkedDate); + query.setParameter("developerId", developerId); + List result = query.getResultList(); + + if (result.size() > 1) { + throw new EntityRetrievalException("Data error. Duplicate checked_date in real_world_testing_plan_summary_by_developer_report table."); + } + + if (result.size() > 0) { + return result.get(0); + } + return null; + } + + private List getDeveloperSummaryEntitiesByRealWorldTestingYear(Long testingYear) { + return entityManager.createQuery( + "from RealWorldTestingPlanSummaryByDeveloperReportEntity rwtps " + + "JOIN FETCH rwtps.developer " + + "where (NOT rwtps.deleted = true) " + + "and rwtps.realWorldTestingYear = :realWorldTestingYear", RealWorldTestingPlanSummaryByDeveloperReportEntity.class) .setParameter("realWorldTestingYear", testingYear) .getResultList(); } diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingReportDataService.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingReportDataService.java index e88c73269e..a87e02e653 100644 --- a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingReportDataService.java +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingReportDataService.java @@ -22,20 +22,40 @@ public RealWorldTestingReportDataService(RealWorldTestingPlanSummaryReportDao re } @Transactional - public List getRealWorldTestingPlanSummaryReports() { - Optional rwtYear = realWorldTestingPlanSummaryReportDao.getMaxRealWorldTestingYear(); + public List getRealWorldTestingPlanSummaryByAcbReports() { + Optional rwtYear = realWorldTestingPlanSummaryReportDao.getMaxRealWorldTestingYearForAcbSummary(); if (rwtYear.isPresent()) { - return realWorldTestingPlanSummaryReportDao.getRealWorldTestingReportsByTestingYear(rwtYear.get()); + return realWorldTestingPlanSummaryReportDao.getRealWorldTestingSummaryByAcbReportsByTestingYear(rwtYear.get()); } else { return List.of(); } } @Transactional - public List getRealWorldTestingResultsSummaryReports() { - Optional rwtYear = realWorldTestingResultsSummaryReportDao.getMaxRealWorldTestingYear(); + public List getRealWorldTestingResultsSummaryByAcbReports() { + Optional rwtYear = realWorldTestingResultsSummaryReportDao.getMaxRealWorldTestingYearForAcbSummary(); if (rwtYear.isPresent()) { - return realWorldTestingResultsSummaryReportDao.getRealWorldTestingReportsByTestingYear(rwtYear.get()); + return realWorldTestingResultsSummaryReportDao.getRealWorldTestingSummaryByAcbReportsByTestingYear(rwtYear.get()); + } else { + return List.of(); + } + } + + @Transactional + public List getRealWorldTestingPlanSummaryByDeveloperReports() { + Optional rwtYear = realWorldTestingPlanSummaryReportDao.getMaxRealWorldTestingYearForDeveloperSummary(); + if (rwtYear.isPresent()) { + return realWorldTestingPlanSummaryReportDao.getRealWorldTestingSummaryByDeveloperReportsByTestingYear(rwtYear.get()); + } else { + return List.of(); + } + } + + @Transactional + public List getRealWorldTestingResultsSummaryByDeveloperReports() { + Optional rwtYear = realWorldTestingResultsSummaryReportDao.getMaxRealWorldTestingYearForDeveloperSummary(); + if (rwtYear.isPresent()) { + return realWorldTestingResultsSummaryReportDao.getRealWorldTestingSummaryByDeveloperReportsByTestingYear(rwtYear.get()); } else { return List.of(); } diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingResultsSummaryReportEntity.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingResultsSummaryByAcbReportEntity.java similarity index 86% rename from chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingResultsSummaryReportEntity.java rename to chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingResultsSummaryByAcbReportEntity.java index 370960fe65..9e52147b3f 100644 --- a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingResultsSummaryReportEntity.java +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingResultsSummaryByAcbReportEntity.java @@ -27,8 +27,8 @@ @AllArgsConstructor @NoArgsConstructor @Entity -@Table(name = "real_world_testing_results_summary_report") -public class RealWorldTestingResultsSummaryReportEntity extends EntityAudit { +@Table(name = "real_world_testing_results_summary_by_acb_report") +public class RealWorldTestingResultsSummaryByAcbReportEntity extends EntityAudit { private static final long serialVersionUID = 4976557989831765742L; @Id @@ -52,8 +52,8 @@ public class RealWorldTestingResultsSummaryReportEntity extends EntityAudit { @Column(name = "requires_check_count") private Long requiresCheckCount; - public RealWorldTestingSummaryReport toDomain() { - return RealWorldTestingSummaryReport.builder() + public RealWorldTestingSummaryByAcbReport toDomain() { + return RealWorldTestingSummaryByAcbReport.builder() .id(id) .realWorldTestingYear(realWorldTestingYear) .certificationBody(certificationBody.toDomain()) diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingResultsSummaryByDeveloperReportEntity.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingResultsSummaryByDeveloperReportEntity.java new file mode 100644 index 0000000000..6011113c15 --- /dev/null +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingResultsSummaryByDeveloperReportEntity.java @@ -0,0 +1,66 @@ +package gov.healthit.chpl.report.realworldtesting; + +import java.time.LocalDate; + +import gov.healthit.chpl.entity.EntityAudit; +import gov.healthit.chpl.entity.developer.DeveloperEntitySimple; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import lombok.experimental.SuperBuilder; + +@Getter +@Setter +@ToString +@SuperBuilder +@AllArgsConstructor +@NoArgsConstructor +@Entity +@Table(name = "real_world_testing_results_summary_by_developer_report") +public class RealWorldTestingResultsSummaryByDeveloperReportEntity extends EntityAudit { + private static final long serialVersionUID = -1208758504334058121L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Column(name = "real_world_testing_year") + private Long realWorldTestingYear; + + @OneToOne(optional = true, fetch = FetchType.LAZY) + @JoinColumn(name = "developer_id") + private DeveloperEntitySimple developer; + + @Column(name = "checked_date") + private LocalDate checkedDate; + + @Column(name = "checked_count") + private Long checkedCount; + + @Column(name = "requires_check_count") + private Long requiresCheckCount; + + public RealWorldTestingSummaryByDeveloperReport toDomain() { + return RealWorldTestingSummaryByDeveloperReport.builder() + .id(id) + .realWorldTestingYear(realWorldTestingYear) + .developerId(developer != null ? developer.getId() : null) + .developerName(developer != null ? developer.getName() : null) + .checkedDate(checkedDate) + .checkedCount(checkedCount) + .requiresCheckCount(requiresCheckCount) + .build(); + } +} diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingResultsSummaryReportDao.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingResultsSummaryReportDao.java index c3ede71113..2c7a01024a 100644 --- a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingResultsSummaryReportDao.java +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingResultsSummaryReportDao.java @@ -8,17 +8,18 @@ import gov.healthit.chpl.dao.impl.BaseDAOImpl; import gov.healthit.chpl.entity.CertificationBodyEntity; +import gov.healthit.chpl.entity.developer.DeveloperEntitySimple; import gov.healthit.chpl.exception.EntityRetrievalException; import jakarta.persistence.Query; @Component public class RealWorldTestingResultsSummaryReportDao extends BaseDAOImpl { - public void save(RealWorldTestingSummaryReport realWorldTestingSummaryReport) throws EntityRetrievalException { - RealWorldTestingResultsSummaryReportEntity entity = getEntityByCheckedDateAndAcb(realWorldTestingSummaryReport.getCheckedDate(), + public void save(RealWorldTestingSummaryByAcbReport realWorldTestingSummaryReport) throws EntityRetrievalException { + RealWorldTestingResultsSummaryByAcbReportEntity entity = getEntityByCheckedDateAndAcb(realWorldTestingSummaryReport.getCheckedDate(), realWorldTestingSummaryReport.getCertificationBody().getId()); if (entity == null) { - entity = RealWorldTestingResultsSummaryReportEntity.builder() + entity = RealWorldTestingResultsSummaryByAcbReportEntity.builder() .realWorldTestingYear(realWorldTestingSummaryReport.getRealWorldTestingYear()) .certificationBody(CertificationBodyEntity.builder() .id(realWorldTestingSummaryReport.getCertificationBody().getId()) @@ -36,29 +37,33 @@ public void save(RealWorldTestingSummaryReport realWorldTestingSummaryReport) th } } - public Optional getMaxRealWorldTestingYear() { + public Optional getMaxRealWorldTestingYearForAcbSummary() { return Optional.ofNullable(entityManager.createQuery( "select MAX(rwtrsr.realWorldTestingYear) " - + "from RealWorldTestingResultsSummaryReportEntity rwtrsr " + + "from RealWorldTestingResultsSummaryByAcbReportEntity rwtrsr " + "where (NOT deleted = true)", Long.class) .getSingleResult()); } - public List getRealWorldTestingReportsByTestingYear(Long realWorldTestingYear) { - return getEntitiesByRealWorldTestingYear(realWorldTestingYear).stream() + public List getRealWorldTestingSummaryByAcbReportsByTestingYear(Long realWorldTestingYear) { + return getAcbSummaryEntitiesByRealWorldTestingYear(realWorldTestingYear).stream() .map(entity -> entity.toDomain()) .toList(); } - private RealWorldTestingResultsSummaryReportEntity getEntity(Long id) throws EntityRetrievalException { + private RealWorldTestingResultsSummaryByAcbReportEntity getEntityByCheckedDateAndAcb(LocalDate checkedDate, Long certificationBodyId) throws EntityRetrievalException { Query query = entityManager.createQuery( - "from RealWorldTestingResultsSummaryReportEntity where (NOT deleted = true) and id = :id", RealWorldTestingResultsSummaryReportEntity.class); - query.setParameter("id", id); - List result = query.getResultList(); + "from RealWorldTestingResultsSummaryByAcbReportEntity rwtrs " + + "where (NOT deleted = true) " + + "and checkedDate = :checkedDate " + + "and rwtrs.certificationBody.id = :certificationBodyId", RealWorldTestingResultsSummaryByAcbReportEntity.class); + query.setParameter("checkedDate", checkedDate); + query.setParameter("certificationBodyId", certificationBodyId); + List result = query.getResultList(); if (result.size() > 1) { - throw new EntityRetrievalException("Data error. Duplicate id in real_world_testing_results_summary_report table."); + throw new EntityRetrievalException("Data error. Duplicate checked_date in real_world_testing_results_summary_by_acb_report table."); } if (result.size() > 0) { @@ -67,18 +72,65 @@ private RealWorldTestingResultsSummaryReportEntity getEntity(Long id) throws Ent return null; } - private RealWorldTestingResultsSummaryReportEntity getEntityByCheckedDateAndAcb(LocalDate checkedDate, Long certificationBodyId) throws EntityRetrievalException { - Query query = entityManager.createQuery( - "from RealWorldTestingResultsSummaryReportEntity rwtrs " + private List getAcbSummaryEntitiesByRealWorldTestingYear(Long testingYear) { + return entityManager.createQuery( + "from RealWorldTestingResultsSummaryByAcbReportEntity rwtrs " + "where (NOT deleted = true) " + + "and rwtrs.realWorldTestingYear = :realWorldTestingYear", RealWorldTestingResultsSummaryByAcbReportEntity.class) + .setParameter("realWorldTestingYear", testingYear) + .getResultList(); + } + + public void save(RealWorldTestingSummaryByDeveloperReport realWorldTestingSummaryReport) throws EntityRetrievalException { + RealWorldTestingResultsSummaryByDeveloperReportEntity entity = getEntityByCheckedDateAndDeveloper(realWorldTestingSummaryReport.getCheckedDate(), + realWorldTestingSummaryReport.getDeveloperId()); + if (entity == null) { + entity = RealWorldTestingResultsSummaryByDeveloperReportEntity.builder() + .realWorldTestingYear(realWorldTestingSummaryReport.getRealWorldTestingYear()) + .developer(DeveloperEntitySimple.builder() + .id(realWorldTestingSummaryReport.getDeveloperId()) + .build()) + .checkedDate(realWorldTestingSummaryReport.getCheckedDate()) + .checkedCount(realWorldTestingSummaryReport.getCheckedCount()) + .requiresCheckCount(realWorldTestingSummaryReport.getRequiresCheckCount()) + .build(); + + create(entity); + } else { + entity.setCheckedCount(realWorldTestingSummaryReport.getCheckedCount()); + entity.setRequiresCheckCount(realWorldTestingSummaryReport.getRequiresCheckCount()); + update(entity); + } + } + + public Optional getMaxRealWorldTestingYearForDeveloperSummary() { + return Optional.ofNullable(entityManager.createQuery( + "select MAX(rwtrsr.realWorldTestingYear) " + + "from RealWorldTestingResultsSummaryByDeveloperReportEntity rwtrsr " + + "where (NOT deleted = true)", Long.class) + .getSingleResult()); + + } + + public List getRealWorldTestingSummaryByDeveloperReportsByTestingYear(Long realWorldTestingYear) { + return getDeveloperSummaryEntitiesByRealWorldTestingYear(realWorldTestingYear).stream() + .map(entity -> entity.toDomain()) + .toList(); + } + + private RealWorldTestingResultsSummaryByDeveloperReportEntity getEntityByCheckedDateAndDeveloper(LocalDate checkedDate, Long developerId) throws EntityRetrievalException { + Query query = entityManager.createQuery( + "from RealWorldTestingResultsSummaryByDeveloperReportEntity rwtrs " + + "JOIN FETCH rwtrs.developer dev " + + "where (NOT rwtrs.deleted = true) " + "and checkedDate = :checkedDate " - + "and rwtrs.certificationBody.id = :certificationBodyId", RealWorldTestingResultsSummaryReportEntity.class); + + "and dev.id = :developerId", RealWorldTestingResultsSummaryByDeveloperReportEntity.class); query.setParameter("checkedDate", checkedDate); - query.setParameter("certificationBodyId", certificationBodyId); - List result = query.getResultList(); + query.setParameter("developerId", developerId); + List result = query.getResultList(); if (result.size() > 1) { - throw new EntityRetrievalException("Data error. Duplicate checked_date in real_world_testing_results_summary_report table."); + throw new EntityRetrievalException("Data error. Duplicate checked_date in real_world_testing_results_by_devleoper_summary_report table."); } if (result.size() > 0) { @@ -87,11 +139,12 @@ private RealWorldTestingResultsSummaryReportEntity getEntityByCheckedDateAndAcb( return null; } - private List getEntitiesByRealWorldTestingYear(Long testingYear) { + private List getDeveloperSummaryEntitiesByRealWorldTestingYear(Long testingYear) { return entityManager.createQuery( - "from RealWorldTestingResultsSummaryReportEntity rwtrs " - + "where (NOT deleted = true) " - + "and rwtrs.realWorldTestingYear = :realWorldTestingYear", RealWorldTestingResultsSummaryReportEntity.class) + "from RealWorldTestingResultsSummaryByDeveloperReportEntity rwtrs " + + "JOIN FETCH rwtrs.developer " + + "where (NOT rwtrs.deleted = true) " + + "and rwtrs.realWorldTestingYear = :realWorldTestingYear", RealWorldTestingResultsSummaryByDeveloperReportEntity.class) .setParameter("realWorldTestingYear", testingYear) .getResultList(); } diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingSummaryReport.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingSummaryByAcbReport.java similarity index 93% rename from chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingSummaryReport.java rename to chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingSummaryByAcbReport.java index b9e19b7eac..a91f942239 100644 --- a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingSummaryReport.java +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingSummaryByAcbReport.java @@ -13,7 +13,7 @@ @Data @Builder -public class RealWorldTestingSummaryReport { +public class RealWorldTestingSummaryByAcbReport { private Long id; private Long realWorldTestingYear; diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingSummaryByDeveloperReport.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingSummaryByDeveloperReport.java new file mode 100644 index 0000000000..e56a97bc44 --- /dev/null +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingSummaryByDeveloperReport.java @@ -0,0 +1,27 @@ +package gov.healthit.chpl.report.realworldtesting; + +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 RealWorldTestingSummaryByDeveloperReport { + private Long id; + + private Long realWorldTestingYear; + private Long developerId; + private String developerName; + + @JsonDeserialize(using = LocalDateDeserializer.class) + @JsonSerialize(using = LocalDateSerializer.class) + private LocalDate checkedDate; + + private Long checkedCount; + private Long requiresCheckCount; +} diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/RealWorldTestingSummaryReportCreatorJob.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/RealWorldTestingSummaryReportCreatorJob.java index 0f2e4a832d..a609a259d1 100644 --- a/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/RealWorldTestingSummaryReportCreatorJob.java +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/RealWorldTestingSummaryReportCreatorJob.java @@ -5,6 +5,7 @@ import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.commons.lang3.tuple.Pair; import org.quartz.JobExecutionContext; @@ -17,13 +18,18 @@ import org.springframework.transaction.support.TransactionTemplate; import org.springframework.web.context.support.SpringBeanAutowiringSupport; +import gov.healthit.chpl.developer.search.ActiveListingSearchOptions; +import gov.healthit.chpl.developer.search.DeveloperSearchRequest; +import gov.healthit.chpl.developer.search.DeveloperSearchResult; +import gov.healthit.chpl.developer.search.DeveloperSearchService; import gov.healthit.chpl.domain.CertificationBody; import gov.healthit.chpl.manager.CertificationBodyManager; import gov.healthit.chpl.realworldtesting.domain.RealWorldTestingReport; import gov.healthit.chpl.realworldtesting.manager.RealWorldTestingReportService; import gov.healthit.chpl.report.realworldtesting.RealWorldTestingPlanSummaryReportDao; import gov.healthit.chpl.report.realworldtesting.RealWorldTestingResultsSummaryReportDao; -import gov.healthit.chpl.report.realworldtesting.RealWorldTestingSummaryReport; +import gov.healthit.chpl.report.realworldtesting.RealWorldTestingSummaryByAcbReport; +import gov.healthit.chpl.report.realworldtesting.RealWorldTestingSummaryByDeveloperReport; import gov.healthit.chpl.util.DateUtil; import lombok.extern.log4j.Log4j2; @@ -42,6 +48,9 @@ public class RealWorldTestingSummaryReportCreatorJob extends QuartzJob { @Autowired private CertificationBodyManager certificationBodyManager; + @Autowired + private DeveloperSearchService developerSearchService; + @Autowired private PlatformTransactionManager transactionManager; @@ -65,8 +74,10 @@ public void execute(JobExecutionContext context) throws JobExecutionException { TransactionOperations transactionOperations = new TransactionTemplate(transactionManager, new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRES_NEW)); transactionOperations.executeWithoutResult(status -> { - processRwtPlanCounts(rwtPlansReports); - processRwtResultsCounts(rwtResultReports); + processRwtPlanCountsByAcb(rwtPlansReports); + processRwtPlanCountsByDeveloper(rwtPlansReports); + processRwtResultsCountsByAcb(rwtResultReports); + processRwtResultsCountsByDeveloper(rwtResultReports); }); } catch (Exception e) { LOGGER.catching(e); @@ -76,7 +87,7 @@ public void execute(JobExecutionContext context) throws JobExecutionException { } - private void processRwtResultsCounts(List reportRows) { + private void processRwtResultsCountsByAcb(List reportRows) { Integer rwtEligibilityYear = LocalDate.now().getYear() - 1; if (!isDateInResultsSubmissionWindow(LocalDate.now(), rwtEligibilityYear)) { @@ -84,7 +95,7 @@ private void processRwtResultsCounts(List reportRows) { return; } - List rwtSummaryReports = new ArrayList(); + List rwtSummaryReports = new ArrayList(); rwtReportService.getResultsStartDate(rwtEligibilityYear).datesUntil(LocalDate.now()).forEach(reportDate -> { certificationBodyManager.getAllActive().forEach(acb -> { @@ -94,17 +105,17 @@ private void processRwtResultsCounts(List reportRows) { && isListingValidAsOfDate(row.getCertificationDate(), reportDate)) .collect(Collectors.counting()); - rwtSummaryReports.add(RealWorldTestingSummaryReport.builder() + rwtSummaryReports.add(RealWorldTestingSummaryByAcbReport.builder() .realWorldTestingYear(rwtEligibilityYear.longValue()) .certificationBody(acb) .checkedDate(reportDate) - .checkedCount(calculateResulltsCount(reportRows, rwtEligibilityYear, acb, reportDate).longValue()) + .checkedCount(calculateResultsCount(reportRows, rwtEligibilityYear, acb, reportDate).longValue()) .requiresCheckCount(eligibleListingCountForAcb) .build()); }); }); - rwtSummaryReports.sort(Comparator.comparing(RealWorldTestingSummaryReport::getCheckedDate) + rwtSummaryReports.sort(Comparator.comparing(RealWorldTestingSummaryByAcbReport::getCheckedDate) .thenComparing((o1, o2) -> o1.getCertificationBody().getId().compareTo(o2.getCertificationBody().getId()))); rwtSummaryReports.forEach(value -> { @@ -118,7 +129,54 @@ && isListingValidAsOfDate(row.getCertificationDate(), reportDate)) LOGGER.info("Completed gathering RWT Results submissions."); } - private void processRwtPlanCounts(List reportRows) { + private void processRwtResultsCountsByDeveloper(List reportRows) { + Integer rwtEligibilityYear = LocalDate.now().getYear() - 1; + + if (!isDateInResultsSubmissionWindow(LocalDate.now(), rwtEligibilityYear)) { + LOGGER.info("Outside the RWT Results submission window. Not collecting data."); + return; + } + + List rwtSummaryReports = new ArrayList(); + + List developersWithActiveListings = developerSearchService.getAllPagesOfSearchResults(DeveloperSearchRequest.builder() + .activeListingsOptions(Stream.of(ActiveListingSearchOptions.HAS_ANY_ACTIVE).collect(Collectors.toSet())) + .build(), LOGGER); + + rwtReportService.getResultsStartDate(rwtEligibilityYear).datesUntil(LocalDate.now()).forEach(reportDate -> { + developersWithActiveListings.stream().forEach(dev -> { + Long eligibleListingCountForDeveloper = reportRows.stream() + .filter(row -> row.getDeveloperId().equals(dev.getId()) + && row.getRwtEligibilityYear() != null + && isListingValidAsOfDate(row.getCertificationDate(), reportDate)) + .collect(Collectors.counting()); + + rwtSummaryReports.add(RealWorldTestingSummaryByDeveloperReport.builder() + .realWorldTestingYear(rwtEligibilityYear.longValue()) + .developerId(dev.getId()) + .developerName(dev.getName()) + .checkedDate(reportDate) + .checkedCount(calculateResultsCount(reportRows, rwtEligibilityYear, dev, reportDate).longValue()) + .requiresCheckCount(eligibleListingCountForDeveloper) + .build()); + }); + }); + + rwtSummaryReports.sort(Comparator.comparing(RealWorldTestingSummaryByDeveloperReport::getCheckedDate) + .thenComparing((o1, o2) -> o1.getDeveloperId().compareTo(o2.getDeveloperId()))); + + rwtSummaryReports.forEach(value -> { + LOGGER.info("{} - {} - {}", value.getCheckedCount(), value.getCheckedDate(), value.getDeveloperName()); + try { + realWorldTestingResultsSummaryReportDao.save(value); + } catch (Exception e) { + LOGGER.error("Could not save RealWorldTestingSummaryReport: {}", value.toString(), e); + } + }); + LOGGER.info("Completed gathering RWT Results submissions."); + } + + private void processRwtPlanCountsByAcb(List reportRows) { Integer rwtEligibilityYear = LocalDate.now().getYear() + 1; if (!isDateInPlansSubmissionWindow(LocalDate.now(), rwtEligibilityYear)) { @@ -126,7 +184,7 @@ private void processRwtPlanCounts(List reportRows) { return; } - List rwtSummaryReports = new ArrayList(); + List rwtSummaryReports = new ArrayList(); rwtReportService.getPlansStartDate(rwtEligibilityYear).datesUntil(LocalDate.now()).forEach(reportDate -> { certificationBodyManager.getAllActive().forEach(acb -> { @@ -136,7 +194,7 @@ private void processRwtPlanCounts(List reportRows) { && isListingValidAsOfDate(row.getCertificationDate(), reportDate)) .collect(Collectors.counting()); - rwtSummaryReports.add(RealWorldTestingSummaryReport.builder() + rwtSummaryReports.add(RealWorldTestingSummaryByAcbReport.builder() .realWorldTestingYear(rwtEligibilityYear.longValue()) .certificationBody(acb) .checkedDate(reportDate) @@ -146,7 +204,7 @@ && isListingValidAsOfDate(row.getCertificationDate(), reportDate)) }); }); - rwtSummaryReports.sort(Comparator.comparing(RealWorldTestingSummaryReport::getCheckedDate) + rwtSummaryReports.sort(Comparator.comparing(RealWorldTestingSummaryByAcbReport::getCheckedDate) .thenComparing((o1, o2) -> o1.getCertificationBody().getId().compareTo(o2.getCertificationBody().getId()))); rwtSummaryReports.forEach(value -> { @@ -160,6 +218,53 @@ && isListingValidAsOfDate(row.getCertificationDate(), reportDate)) LOGGER.info("Completed gathering RWT Plan submissions."); } + private void processRwtPlanCountsByDeveloper(List reportRows) { + Integer rwtEligibilityYear = LocalDate.now().getYear() + 1; + + if (!isDateInPlansSubmissionWindow(LocalDate.now(), rwtEligibilityYear)) { + LOGGER.info("Outside the RWT Plan submission window. Not collecting data."); + return; + } + + List rwtSummaryReports = new ArrayList(); + + List developersWithActiveListings = developerSearchService.getAllPagesOfSearchResults(DeveloperSearchRequest.builder() + .activeListingsOptions(Stream.of(ActiveListingSearchOptions.HAS_ANY_ACTIVE).collect(Collectors.toSet())) + .build(), LOGGER); + + rwtReportService.getPlansStartDate(rwtEligibilityYear).datesUntil(LocalDate.now()).forEach(reportDate -> { + developersWithActiveListings.stream().forEach(dev -> { + Long eligibleListingCountForDeveloper = reportRows.stream() + .filter(row -> row.getDeveloperId().equals(dev.getId()) + && row.getRwtEligibilityYear() != null + && isListingValidAsOfDate(row.getCertificationDate(), reportDate)) + .collect(Collectors.counting()); + + rwtSummaryReports.add(RealWorldTestingSummaryByDeveloperReport.builder() + .realWorldTestingYear(rwtEligibilityYear.longValue()) + .developerId(dev.getId()) + .developerName(dev.getName()) + .checkedDate(reportDate) + .checkedCount(calculatePlanCount(reportRows, rwtEligibilityYear, dev, reportDate).longValue()) + .requiresCheckCount(eligibleListingCountForDeveloper) + .build()); + }); + }); + + rwtSummaryReports.sort(Comparator.comparing(RealWorldTestingSummaryByDeveloperReport::getCheckedDate) + .thenComparing((o1, o2) -> o1.getDeveloperId().compareTo(o2.getDeveloperId()))); + + rwtSummaryReports.forEach(value -> { + LOGGER.info("{} - {} - {}", value.getCheckedCount(), value.getCheckedDate(), value.getDeveloperName()); + try { + realWorldTestingPlanSummaryReportDao.save(value); + } catch (Exception e) { + LOGGER.error("Could not save RealWorldTestingSummaryReport: {}", value.toString(), e); + } + }); + LOGGER.info("Completed gathering RWT Plan submissions."); + } + private Integer calculatePlanCount(List reports, Integer rwtYear, CertificationBody acb, LocalDate checkedDate) { return reports.stream() .filter(report -> report.getAcbName().equals(acb.getName()) @@ -170,7 +275,17 @@ private Integer calculatePlanCount(List reports, Integer .size(); } - private Integer calculateResulltsCount(List reports, Integer rwtYear, CertificationBody acb, LocalDate checkedDate) { + private Integer calculatePlanCount(List reports, Integer rwtYear, DeveloperSearchResult dev, LocalDate checkedDate) { + return reports.stream() + .filter(report -> report.getDeveloperId().equals(dev.getId()) + && report.getRwtEligibilityYear() != null + && DateUtil.isDateBetweenInclusive(Pair.of(rwtReportService.getPlansStartDate(rwtYear), checkedDate), + report.getRwtPlansCheckDate())) + .toList() + .size(); + } + + private Integer calculateResultsCount(List reports, Integer rwtYear, CertificationBody acb, LocalDate checkedDate) { return reports.stream() .filter(report -> report.getAcbName().equals(acb.getName()) && report.getRwtEligibilityYear() != null @@ -180,6 +295,16 @@ private Integer calculateResulltsCount(List reports, Int .size(); } + private Integer calculateResultsCount(List reports, Integer rwtYear, DeveloperSearchResult dev, LocalDate checkedDate) { + return reports.stream() + .filter(report -> report.getDeveloperId().equals(dev.getId()) + && report.getRwtEligibilityYear() != null + && DateUtil.isDateBetweenInclusive(Pair.of(rwtReportService.getResultsStartDate(rwtYear), checkedDate), + report.getRwtResultsCheckDate())) + .toList() + .size(); + } + private boolean isDateInPlansSubmissionWindow(LocalDate dateToTest, Integer rwtYear) { return DateUtil.isDateBetweenInclusive(Pair.of(rwtReportService.getPlansStartDate(rwtYear), rwtReportService.getPlansLateDate(rwtYear)), dateToTest); } diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/onetime/RwtPopulateMissingDataCreatorJob.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/onetime/RwtPopulateMissingDataCreatorJob.java index e405adb94f..268905ec6e 100644 --- a/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/onetime/RwtPopulateMissingDataCreatorJob.java +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/onetime/RwtPopulateMissingDataCreatorJob.java @@ -22,7 +22,7 @@ import gov.healthit.chpl.realworldtesting.domain.RealWorldTestingReport; import gov.healthit.chpl.realworldtesting.manager.RealWorldTestingReportService; import gov.healthit.chpl.report.realworldtesting.RealWorldTestingResultsSummaryReportDao; -import gov.healthit.chpl.report.realworldtesting.RealWorldTestingSummaryReport; +import gov.healthit.chpl.report.realworldtesting.RealWorldTestingSummaryByAcbReport; import gov.healthit.chpl.scheduler.job.QuartzJob; import gov.healthit.chpl.util.DateUtil; import lombok.extern.log4j.Log4j2; @@ -76,7 +76,7 @@ private void processRwtResultsCounts(List reportRows) { return; } - List rwtSummaryReports = new ArrayList(); + List rwtSummaryReports = new ArrayList(); rwtReportService.getResultsStartDate(rwtEligibilityYear).datesUntil(lastDayOfResultsSubmissionWindow.plusDays(1)).forEach(reportDate -> { certificationBodyManager.getAllActive().forEach(acb -> { @@ -86,7 +86,7 @@ private void processRwtResultsCounts(List reportRows) { && isListingValidAsOfDate(row.getCertificationDate(), reportDate)) .collect(Collectors.counting()); - rwtSummaryReports.add(RealWorldTestingSummaryReport.builder() + rwtSummaryReports.add(RealWorldTestingSummaryByAcbReport.builder() .realWorldTestingYear(rwtEligibilityYear.longValue()) .certificationBody(acb) .checkedDate(reportDate) @@ -96,7 +96,7 @@ && isListingValidAsOfDate(row.getCertificationDate(), reportDate)) }); }); - rwtSummaryReports.sort(Comparator.comparing(RealWorldTestingSummaryReport::getCheckedDate) + rwtSummaryReports.sort(Comparator.comparing(RealWorldTestingSummaryByAcbReport::getCheckedDate) .thenComparing((o1, o2) -> o1.getCertificationBody().getId().compareTo(o2.getCertificationBody().getId()))); rwtSummaryReports.forEach(value -> { From f5e2900adb443cc39f9e91899960b6ce2cce7649 Mon Sep 17 00:00:00 2001 From: Katy Ekey Date: Wed, 6 May 2026 15:54:07 -0400 Subject: [PATCH 2/7] fix: HQL typos and other bugs [#OCD-5225] --- .../realworldtesting/RealWorldTestingPlanSummaryReportDao.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingPlanSummaryReportDao.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingPlanSummaryReportDao.java index 2ea9cf046a..5d8325ff6e 100644 --- a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingPlanSummaryReportDao.java +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingPlanSummaryReportDao.java @@ -124,7 +124,7 @@ private RealWorldTestingPlanSummaryByDeveloperReportEntity getEntityByCheckedDat + "JOIN FETCH rwtps.developer dev " + "where (NOT rwtps.deleted = true) " + "and rwtps.checkedDate = :checkedDate " - + "and dev.id = :developerId", RealWorldTestingPlanSummaryByAcbReportEntity.class); + + "and dev.id = :developerId", RealWorldTestingPlanSummaryByDeveloperReportEntity.class); query.setParameter("checkedDate", checkedDate); query.setParameter("developerId", developerId); List result = query.getResultList(); From ce8c7f15a7b89cfaf6315d16f84f109d29acd02f Mon Sep 17 00:00:00 2001 From: Katy Ekey Date: Fri, 8 May 2026 10:10:49 -0400 Subject: [PATCH 3/7] fix: Logging issue in RWT Summary Creator Job [#OCD-5225] --- .../job/RealWorldTestingSummaryReportCreatorJob.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/RealWorldTestingSummaryReportCreatorJob.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/RealWorldTestingSummaryReportCreatorJob.java index a609a259d1..39f95e8998 100644 --- a/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/RealWorldTestingSummaryReportCreatorJob.java +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/RealWorldTestingSummaryReportCreatorJob.java @@ -57,7 +57,7 @@ public class RealWorldTestingSummaryReportCreatorJob extends QuartzJob { @Override public void execute(JobExecutionContext context) throws JobExecutionException { SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); - LOGGER.info("********* Starting the Real World Report Creator job for " + context.getMergedJobDataMap().getString("email") + " *********"); + LOGGER.info("********* Starting the Real World Testing Summary Report Creator job *********"); try { List activeAcbIds = certificationBodyManager.getAllActive().stream() .map(acb -> acb.getId()) @@ -82,7 +82,7 @@ public void execute(JobExecutionContext context) throws JobExecutionException { } catch (Exception e) { LOGGER.catching(e); } finally { - LOGGER.info("********* Completed the Real World Report Creator job. *********"); + LOGGER.info("********* Completed the Real World Testing Summary Report Creator job. *********"); } } From 4841d4e5d976cb498f1234768f5e3ae2e6bf091f Mon Sep 17 00:00:00 2001 From: Katy Ekey Date: Fri, 22 May 2026 10:16:12 -0400 Subject: [PATCH 4/7] feat: Remove RWT plan summary by developer endpoint, data gathering [#OCD-5225] --- .../RealWorldTestingReportController.java | 11 ---- ...ingPlanSummaryByDeveloperReportEntity.java | 66 ------------------- .../RealWorldTestingPlanSummaryReportDao.java | 61 ----------------- .../RealWorldTestingReportDataService.java | 10 --- ...alWorldTestingSummaryReportCreatorJob.java | 58 ---------------- 5 files changed, 206 deletions(-) delete mode 100644 chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingPlanSummaryByDeveloperReportEntity.java diff --git a/chpl/chpl-api/src/main/java/gov/healthit/chpl/web/controller/RealWorldTestingReportController.java b/chpl/chpl-api/src/main/java/gov/healthit/chpl/web/controller/RealWorldTestingReportController.java index aa7f5b8a99..01079cf06a 100644 --- a/chpl/chpl-api/src/main/java/gov/healthit/chpl/web/controller/RealWorldTestingReportController.java +++ b/chpl/chpl-api/src/main/java/gov/healthit/chpl/web/controller/RealWorldTestingReportController.java @@ -53,17 +53,6 @@ public RealWorldTestingReportController(ReportDataManager reportDataManager) { return reportDataManager.getRealWorldTestingReportDataService().getRealWorldTestingResultsSummaryByAcbReports(); } - @Operation(summary = "Retrieves the data used to generate the Real World Testing Plans summary by Developer report.", - description = "Retrieves the data used to generate the Real World Testing Plans summary by Developer report.", - security = { - @SecurityRequirement(name = SwaggerSecurityRequirement.API_KEY) - }) - @LogMethodUsage - @RequestMapping(value = "/plans-summary-by-developer", method = RequestMethod.GET, produces = "application/json; charset=utf-8") - public @ResponseBody List getRealWorldTestingPlanSummaryByDeveloperReports() { - return reportDataManager.getRealWorldTestingReportDataService().getRealWorldTestingPlanSummaryByDeveloperReports(); - } - @Operation(summary = "Retrieves the data used to generate the Real World Testing Results summary by Developer report.", description = "Retrieves the data used to generate the Real World Testing Results summary by Developer report.", security = { diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingPlanSummaryByDeveloperReportEntity.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingPlanSummaryByDeveloperReportEntity.java deleted file mode 100644 index 861b10e7f3..0000000000 --- a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingPlanSummaryByDeveloperReportEntity.java +++ /dev/null @@ -1,66 +0,0 @@ -package gov.healthit.chpl.report.realworldtesting; - -import java.time.LocalDate; - -import gov.healthit.chpl.entity.EntityAudit; -import gov.healthit.chpl.entity.developer.DeveloperEntitySimple; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.OneToOne; -import jakarta.persistence.Table; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.ToString; -import lombok.experimental.SuperBuilder; - -@Getter -@Setter -@ToString -@SuperBuilder -@AllArgsConstructor -@NoArgsConstructor -@Entity -@Table(name = "real_world_testing_plan_summary_by_developer_report") -public class RealWorldTestingPlanSummaryByDeveloperReportEntity extends EntityAudit { - private static final long serialVersionUID = -1291758504534058893L; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "id") - private Long id; - - @Column(name = "real_world_testing_year") - private Long realWorldTestingYear; - - @OneToOne(optional = true, fetch = FetchType.LAZY) - @JoinColumn(name = "developer_id") - private DeveloperEntitySimple developer; - - @Column(name = "checked_date") - private LocalDate checkedDate; - - @Column(name = "checked_count") - private Long checkedCount; - - @Column(name = "requires_check_count") - private Long requiresCheckCount; - - public RealWorldTestingSummaryByDeveloperReport toDomain() { - return RealWorldTestingSummaryByDeveloperReport.builder() - .id(id) - .realWorldTestingYear(realWorldTestingYear) - .developerId(developer != null ? developer.getId() : null) - .developerName(developer != null ? developer.getName() : null) - .checkedDate(checkedDate) - .checkedCount(checkedCount) - .requiresCheckCount(requiresCheckCount) - .build(); - } -} diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingPlanSummaryReportDao.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingPlanSummaryReportDao.java index 5d8325ff6e..3e5e0e7a49 100644 --- a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingPlanSummaryReportDao.java +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingPlanSummaryReportDao.java @@ -8,7 +8,6 @@ import gov.healthit.chpl.dao.impl.BaseDAOImpl; import gov.healthit.chpl.entity.CertificationBodyEntity; -import gov.healthit.chpl.entity.developer.DeveloperEntitySimple; import gov.healthit.chpl.exception.EntityRetrievalException; import jakarta.persistence.Query; @@ -81,28 +80,6 @@ private List getAcbSummaryEntities .getResultList(); } - public void save(RealWorldTestingSummaryByDeveloperReport realWorldTestingSummaryReport) throws EntityRetrievalException { - RealWorldTestingPlanSummaryByDeveloperReportEntity entity = getEntityByCheckedDateAndDeveloper(realWorldTestingSummaryReport.getCheckedDate(), - realWorldTestingSummaryReport.getDeveloperId()); - if (entity == null) { - entity = RealWorldTestingPlanSummaryByDeveloperReportEntity.builder() - .realWorldTestingYear(realWorldTestingSummaryReport.getRealWorldTestingYear()) - .developer(DeveloperEntitySimple.builder() - .id(realWorldTestingSummaryReport.getDeveloperId()) - .build()) - .checkedDate(realWorldTestingSummaryReport.getCheckedDate()) - .checkedCount(realWorldTestingSummaryReport.getCheckedCount()) - .requiresCheckCount(realWorldTestingSummaryReport.getRequiresCheckCount()) - .build(); - - create(entity); - } else { - entity.setCheckedCount(realWorldTestingSummaryReport.getCheckedCount()); - entity.setRequiresCheckCount(realWorldTestingSummaryReport.getRequiresCheckCount()); - update(entity); - } - } - public Optional getMaxRealWorldTestingYearForDeveloperSummary() { return Optional.ofNullable(entityManager.createQuery( "select MAX(rwtpsr.realWorldTestingYear) " @@ -111,42 +88,4 @@ public Optional getMaxRealWorldTestingYearForDeveloperSummary() { .getSingleResult()); } - - public List getRealWorldTestingSummaryByDeveloperReportsByTestingYear(Long realWorldTestingYear) { - return getDeveloperSummaryEntitiesByRealWorldTestingYear(realWorldTestingYear).stream() - .map(entity -> entity.toDomain()) - .toList(); - } - - private RealWorldTestingPlanSummaryByDeveloperReportEntity getEntityByCheckedDateAndDeveloper(LocalDate checkedDate, Long developerId) throws EntityRetrievalException { - Query query = entityManager.createQuery( - "from RealWorldTestingPlanSummaryByDeveloperReportEntity rwtps " - + "JOIN FETCH rwtps.developer dev " - + "where (NOT rwtps.deleted = true) " - + "and rwtps.checkedDate = :checkedDate " - + "and dev.id = :developerId", RealWorldTestingPlanSummaryByDeveloperReportEntity.class); - query.setParameter("checkedDate", checkedDate); - query.setParameter("developerId", developerId); - List result = query.getResultList(); - - if (result.size() > 1) { - throw new EntityRetrievalException("Data error. Duplicate checked_date in real_world_testing_plan_summary_by_developer_report table."); - } - - if (result.size() > 0) { - return result.get(0); - } - return null; - } - - private List getDeveloperSummaryEntitiesByRealWorldTestingYear(Long testingYear) { - return entityManager.createQuery( - "from RealWorldTestingPlanSummaryByDeveloperReportEntity rwtps " - + "JOIN FETCH rwtps.developer " - + "where (NOT rwtps.deleted = true) " - + "and rwtps.realWorldTestingYear = :realWorldTestingYear", RealWorldTestingPlanSummaryByDeveloperReportEntity.class) - .setParameter("realWorldTestingYear", testingYear) - .getResultList(); - } - } diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingReportDataService.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingReportDataService.java index a87e02e653..f99fdbe25f 100644 --- a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingReportDataService.java +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/realworldtesting/RealWorldTestingReportDataService.java @@ -41,16 +41,6 @@ public List getRealWorldTestingResultsSummar } } - @Transactional - public List getRealWorldTestingPlanSummaryByDeveloperReports() { - Optional rwtYear = realWorldTestingPlanSummaryReportDao.getMaxRealWorldTestingYearForDeveloperSummary(); - if (rwtYear.isPresent()) { - return realWorldTestingPlanSummaryReportDao.getRealWorldTestingSummaryByDeveloperReportsByTestingYear(rwtYear.get()); - } else { - return List.of(); - } - } - @Transactional public List getRealWorldTestingResultsSummaryByDeveloperReports() { Optional rwtYear = realWorldTestingResultsSummaryReportDao.getMaxRealWorldTestingYearForDeveloperSummary(); diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/RealWorldTestingSummaryReportCreatorJob.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/RealWorldTestingSummaryReportCreatorJob.java index 39f95e8998..d43d342ddd 100644 --- a/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/RealWorldTestingSummaryReportCreatorJob.java +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/RealWorldTestingSummaryReportCreatorJob.java @@ -75,7 +75,6 @@ public void execute(JobExecutionContext context) throws JobExecutionException { new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRES_NEW)); transactionOperations.executeWithoutResult(status -> { processRwtPlanCountsByAcb(rwtPlansReports); - processRwtPlanCountsByDeveloper(rwtPlansReports); processRwtResultsCountsByAcb(rwtResultReports); processRwtResultsCountsByDeveloper(rwtResultReports); }); @@ -218,53 +217,6 @@ && isListingValidAsOfDate(row.getCertificationDate(), reportDate)) LOGGER.info("Completed gathering RWT Plan submissions."); } - private void processRwtPlanCountsByDeveloper(List reportRows) { - Integer rwtEligibilityYear = LocalDate.now().getYear() + 1; - - if (!isDateInPlansSubmissionWindow(LocalDate.now(), rwtEligibilityYear)) { - LOGGER.info("Outside the RWT Plan submission window. Not collecting data."); - return; - } - - List rwtSummaryReports = new ArrayList(); - - List developersWithActiveListings = developerSearchService.getAllPagesOfSearchResults(DeveloperSearchRequest.builder() - .activeListingsOptions(Stream.of(ActiveListingSearchOptions.HAS_ANY_ACTIVE).collect(Collectors.toSet())) - .build(), LOGGER); - - rwtReportService.getPlansStartDate(rwtEligibilityYear).datesUntil(LocalDate.now()).forEach(reportDate -> { - developersWithActiveListings.stream().forEach(dev -> { - Long eligibleListingCountForDeveloper = reportRows.stream() - .filter(row -> row.getDeveloperId().equals(dev.getId()) - && row.getRwtEligibilityYear() != null - && isListingValidAsOfDate(row.getCertificationDate(), reportDate)) - .collect(Collectors.counting()); - - rwtSummaryReports.add(RealWorldTestingSummaryByDeveloperReport.builder() - .realWorldTestingYear(rwtEligibilityYear.longValue()) - .developerId(dev.getId()) - .developerName(dev.getName()) - .checkedDate(reportDate) - .checkedCount(calculatePlanCount(reportRows, rwtEligibilityYear, dev, reportDate).longValue()) - .requiresCheckCount(eligibleListingCountForDeveloper) - .build()); - }); - }); - - rwtSummaryReports.sort(Comparator.comparing(RealWorldTestingSummaryByDeveloperReport::getCheckedDate) - .thenComparing((o1, o2) -> o1.getDeveloperId().compareTo(o2.getDeveloperId()))); - - rwtSummaryReports.forEach(value -> { - LOGGER.info("{} - {} - {}", value.getCheckedCount(), value.getCheckedDate(), value.getDeveloperName()); - try { - realWorldTestingPlanSummaryReportDao.save(value); - } catch (Exception e) { - LOGGER.error("Could not save RealWorldTestingSummaryReport: {}", value.toString(), e); - } - }); - LOGGER.info("Completed gathering RWT Plan submissions."); - } - private Integer calculatePlanCount(List reports, Integer rwtYear, CertificationBody acb, LocalDate checkedDate) { return reports.stream() .filter(report -> report.getAcbName().equals(acb.getName()) @@ -275,16 +227,6 @@ private Integer calculatePlanCount(List reports, Integer .size(); } - private Integer calculatePlanCount(List reports, Integer rwtYear, DeveloperSearchResult dev, LocalDate checkedDate) { - return reports.stream() - .filter(report -> report.getDeveloperId().equals(dev.getId()) - && report.getRwtEligibilityYear() != null - && DateUtil.isDateBetweenInclusive(Pair.of(rwtReportService.getPlansStartDate(rwtYear), checkedDate), - report.getRwtPlansCheckDate())) - .toList() - .size(); - } - private Integer calculateResultsCount(List reports, Integer rwtYear, CertificationBody acb, LocalDate checkedDate) { return reports.stream() .filter(report -> report.getAcbName().equals(acb.getName()) From a6eb2b5a627694880b67932f372cb2c5789627d4 Mon Sep 17 00:00:00 2001 From: Katy Ekey Date: Fri, 22 May 2026 12:38:01 -0400 Subject: [PATCH 5/7] fix: Use correct ONC-ACB terminology [#OCD-5225] --- .../web/controller/RealWorldTestingReportController.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/chpl/chpl-api/src/main/java/gov/healthit/chpl/web/controller/RealWorldTestingReportController.java b/chpl/chpl-api/src/main/java/gov/healthit/chpl/web/controller/RealWorldTestingReportController.java index 01079cf06a..6189862154 100644 --- a/chpl/chpl-api/src/main/java/gov/healthit/chpl/web/controller/RealWorldTestingReportController.java +++ b/chpl/chpl-api/src/main/java/gov/healthit/chpl/web/controller/RealWorldTestingReportController.java @@ -31,8 +31,8 @@ public RealWorldTestingReportController(ReportDataManager reportDataManager) { this.reportDataManager = reportDataManager; } - @Operation(summary = "Retrieves the data used to generate the Real World Testing Plans summary by ACB report.", - description = "Retrieves the data used to generate the Real World Testing Plans summary by ACB report.", + @Operation(summary = "Retrieves the data used to generate the Real World Testing Plans summary by ONC-ACB report.", + description = "Retrieves the data used to generate the Real World Testing Plans summary by ONC-ACB report.", security = { @SecurityRequirement(name = SwaggerSecurityRequirement.API_KEY) }) @@ -42,8 +42,8 @@ public RealWorldTestingReportController(ReportDataManager reportDataManager) { return reportDataManager.getRealWorldTestingReportDataService().getRealWorldTestingPlanSummaryByAcbReports(); } - @Operation(summary = "Retrieves the data used to generate the Real World Testing Results summary by ACB report.", - description = "Retrieves the data used to generate the Real World Testing Results summary by ACB report.", + @Operation(summary = "Retrieves the data used to generate the Real World Testing Results summary by ONC-ACB report.", + description = "Retrieves the data used to generate the Real World Testing Results summary by ONC-ACB report.", security = { @SecurityRequirement(name = SwaggerSecurityRequirement.API_KEY) }) From c6b042af4da6a80ad1cf628bbabbf90d95014f33 Mon Sep 17 00:00:00 2001 From: Katy Ekey Date: Fri, 29 May 2026 13:07:00 -0400 Subject: [PATCH 6/7] fix: Continue collecting RWT Results Summary data for 3 months Katie C said that would be most useful after the submission window ends [#OCD-5225] --- .../src/main/resources/environment.properties | 2 ++ .../manager/RealWorldTestingReportService.java | 7 +++++++ .../job/RealWorldTestingSummaryReportCreatorJob.java | 12 ++++++------ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/chpl/chpl-resources/src/main/resources/environment.properties b/chpl/chpl-resources/src/main/resources/environment.properties index 3fb8355a97..4d770153d6 100644 --- a/chpl/chpl-resources/src/main/resources/environment.properties +++ b/chpl/chpl-resources/src/main/resources/environment.properties @@ -230,6 +230,8 @@ rwtPlanDueDate=12/15 rwtResultsStartDayOfYear=01/01 # Date when the Results is considered late - Format is MM/DD rwtResultsDueDate=03/15 +#Date when we stop gathering summary data about RWT results submissions, used in charts +rwtResultsDataGatheringEndDate=06/15 #Criteria that make a listing eligible for rwt realWorldTestingCriteriaKeys={2021: 'criterion.170_315_b_1_old,\ diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/realworldtesting/manager/RealWorldTestingReportService.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/realworldtesting/manager/RealWorldTestingReportService.java index 2f16485669..f56c77c553 100644 --- a/chpl/chpl-service/src/main/java/gov/healthit/chpl/realworldtesting/manager/RealWorldTestingReportService.java +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/realworldtesting/manager/RealWorldTestingReportService.java @@ -294,6 +294,13 @@ public LocalDate getResultsLateDate(Integer rwtEligYear) { return LocalDate.parse(mmddyyyy, formatter); } + public LocalDate getResultsDataGatheringStopDate(Integer rwtEligYear) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy"); + String mmdd = env.getProperty("rwtResultsDataGatheringEndDate"); + String mmddyyyy = mmdd + "/" + String.valueOf(rwtEligYear + 1); + return LocalDate.parse(mmddyyyy, formatter); + } + private boolean isWithdrawn(RealWorldTestingReport record) { String statusName = record.getCurrentStatus(); return withdrawnStatuses.stream() diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/RealWorldTestingSummaryReportCreatorJob.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/RealWorldTestingSummaryReportCreatorJob.java index d43d342ddd..60be011a8f 100644 --- a/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/RealWorldTestingSummaryReportCreatorJob.java +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/RealWorldTestingSummaryReportCreatorJob.java @@ -89,8 +89,8 @@ public void execute(JobExecutionContext context) throws JobExecutionException { private void processRwtResultsCountsByAcb(List reportRows) { Integer rwtEligibilityYear = LocalDate.now().getYear() - 1; - if (!isDateInResultsSubmissionWindow(LocalDate.now(), rwtEligibilityYear)) { - LOGGER.info("Outside the RWT Results submission window. Not collecting data."); + if (!isDateInResultsDataCollectionWindow(LocalDate.now(), rwtEligibilityYear)) { + LOGGER.info("Outside the RWT Results data collection window. Not collecting data."); return; } @@ -131,8 +131,8 @@ && isListingValidAsOfDate(row.getCertificationDate(), reportDate)) private void processRwtResultsCountsByDeveloper(List reportRows) { Integer rwtEligibilityYear = LocalDate.now().getYear() - 1; - if (!isDateInResultsSubmissionWindow(LocalDate.now(), rwtEligibilityYear)) { - LOGGER.info("Outside the RWT Results submission window. Not collecting data."); + if (!isDateInResultsDataCollectionWindow(LocalDate.now(), rwtEligibilityYear)) { + LOGGER.info("Outside the RWT Results data collection window. Not collecting data."); return; } @@ -251,8 +251,8 @@ private boolean isDateInPlansSubmissionWindow(LocalDate dateToTest, Integer rwtY return DateUtil.isDateBetweenInclusive(Pair.of(rwtReportService.getPlansStartDate(rwtYear), rwtReportService.getPlansLateDate(rwtYear)), dateToTest); } - private boolean isDateInResultsSubmissionWindow(LocalDate dateToTest, Integer rwtYear) { - return DateUtil.isDateBetweenInclusive(Pair.of(rwtReportService.getResultsStartDate(rwtYear), rwtReportService.getResultsLateDate(rwtYear)), dateToTest); + private boolean isDateInResultsDataCollectionWindow(LocalDate dateToTest, Integer rwtYear) { + return DateUtil.isDateBetweenInclusive(Pair.of(rwtReportService.getResultsStartDate(rwtYear), rwtReportService.getResultsDataGatheringStopDate(rwtYear)), dateToTest); } private Boolean isListingValidAsOfDate(LocalDate listingCertificationDate, LocalDate date) { From 8f156c73bbbe5293d9a086fa2bf4555fd3b79078 Mon Sep 17 00:00:00 2001 From: Katy Ekey Date: Tue, 2 Jun 2026 17:07:56 -0400 Subject: [PATCH 7/7] feat: Collect RWT Results data until 7/15 [#OCD-5225] --- chpl/chpl-resources/src/main/resources/environment.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chpl/chpl-resources/src/main/resources/environment.properties b/chpl/chpl-resources/src/main/resources/environment.properties index 4d770153d6..55b976cd47 100644 --- a/chpl/chpl-resources/src/main/resources/environment.properties +++ b/chpl/chpl-resources/src/main/resources/environment.properties @@ -231,7 +231,7 @@ rwtResultsStartDayOfYear=01/01 # Date when the Results is considered late - Format is MM/DD rwtResultsDueDate=03/15 #Date when we stop gathering summary data about RWT results submissions, used in charts -rwtResultsDataGatheringEndDate=06/15 +rwtResultsDataGatheringEndDate=07/15 #Criteria that make a listing eligible for rwt realWorldTestingCriteriaKeys={2021: 'criterion.170_315_b_1_old,\