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 50208effbe..2ac3e538b9 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 @@ -28,6 +28,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.scheduler.job.report.attestation.AttestationReport; import gov.healthit.chpl.scheduler.job.summarystatistics.data.CertificationBodyStatistic; import gov.healthit.chpl.search.domain.ListingSearchResult; import gov.healthit.chpl.util.SwaggerSecurityRequirement; @@ -462,4 +463,14 @@ public ReportDataController(ReportDataManager reportDataManager, DeveloperSearch return reportDataManager.getDirectReviewCounts(); } + @Operation(summary = "Retrieves the data used to generate the Attestations report.", + description = "Retrieves the data used to generate the Attestations report.", + security = { + @SecurityRequirement(name = SwaggerSecurityRequirement.API_KEY) + }) + @RequestMapping(value = "/attestations", method = RequestMethod.GET, produces = "application/json; charset=utf-8") + public @ResponseBody List getAttestationReports() { + return reportDataManager.getAttestationReports(); + } + } diff --git a/chpl/chpl-api/src/main/resources/log4j2-xinclude-file-appenders-console.xml b/chpl/chpl-api/src/main/resources/log4j2-xinclude-file-appenders-console.xml index e7ecece164..ddc8e4ef8e 100644 --- a/chpl/chpl-api/src/main/resources/log4j2-xinclude-file-appenders-console.xml +++ b/chpl/chpl-api/src/main/resources/log4j2-xinclude-file-appenders-console.xml @@ -475,6 +475,13 @@ + + + + + + + diff --git a/chpl/chpl-api/src/main/resources/log4j2-xinclude-file-appenders.xml b/chpl/chpl-api/src/main/resources/log4j2-xinclude-file-appenders.xml index 1b272c6210..d1d537b166 100644 --- a/chpl/chpl-api/src/main/resources/log4j2-xinclude-file-appenders.xml +++ b/chpl/chpl-api/src/main/resources/log4j2-xinclude-file-appenders.xml @@ -808,6 +808,18 @@ interval="1" modulate="true" /> + + + %d{ISO8601} %-5p (%t) [%C{1}(%M:%L)] %m%n + + + + + + + + diff --git a/chpl/chpl-api/src/main/resources/log4j2-xinclude-loggers.xml b/chpl/chpl-api/src/main/resources/log4j2-xinclude-loggers.xml index 61b5a94ad7..eec409eb68 100644 --- a/chpl/chpl-api/src/main/resources/log4j2-xinclude-loggers.xml +++ b/chpl/chpl-api/src/main/resources/log4j2-xinclude-loggers.xml @@ -262,6 +262,10 @@ + + + + diff --git a/chpl/chpl-resources/src/main/resources/environment.properties b/chpl/chpl-resources/src/main/resources/environment.properties index 328008aa79..813443e0e7 100644 --- a/chpl/chpl-resources/src/main/resources/environment.properties +++ b/chpl/chpl-resources/src/main/resources/environment.properties @@ -360,6 +360,7 @@ apiCriteriaKeys=criterion.170_315_g_7,\ ###### Attestations ###### attestationExceptionWindowInDays=5 +attestationApprovalWindowInDays=30 #################################### ###### Redis Connection Properties ###### diff --git a/chpl/chpl-resources/src/main/resources/jobs.xml b/chpl/chpl-resources/src/main/resources/jobs.xml index 8e4c099580..02daaf75ff 100644 --- a/chpl/chpl-resources/src/main/resources/jobs.xml +++ b/chpl/chpl-resources/src/main/resources/jobs.xml @@ -922,6 +922,15 @@ false + + attestationReportCreatorJob + systemJobs + Generate data for the Attestation Report (Power BI) + gov.healthit.chpl.scheduler.job.report.attestation.AttestationReportCreatorJob + true + false + + fixDatadogUrlUptimeAssertionsJob systemJobs diff --git a/chpl/chpl-resources/src/main/resources/system-triggers.xml b/chpl/chpl-resources/src/main/resources/system-triggers.xml index 0c3c528900..eb75d67bae 100644 --- a/chpl/chpl-resources/src/main/resources/system-triggers.xml +++ b/chpl/chpl-resources/src/main/resources/system-triggers.xml @@ -245,5 +245,15 @@ 0 30 6 * * ? + + + attestationReportCreator + AttestationReportCreatorJobTrigger + attestationReportCreatorJob + systemJobs + MISFIRE_INSTRUCTION_DO_NOTHING + 0 30 10 * * ? + + diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/changerequest/dao/DeveloperCertificationBodyMapDAO.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/changerequest/dao/DeveloperCertificationBodyMapDAO.java index 2cd665b69c..2c8be77852 100644 --- a/chpl/chpl-service/src/main/java/gov/healthit/chpl/changerequest/dao/DeveloperCertificationBodyMapDAO.java +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/changerequest/dao/DeveloperCertificationBodyMapDAO.java @@ -1,6 +1,9 @@ package gov.healthit.chpl.changerequest.dao; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import org.springframework.stereotype.Repository; @@ -47,4 +50,26 @@ public List getDevelopersForCertificationBody(Long certificationBodyI .map(item -> item.getDeveloper().toDomain()) .collect(Collectors.toList()); } + + public Map> getCertificationBodiesForAllDeveloper() { + String hql = "SELECT main " + + "FROM DeveloperCertificationBodyMapEntity main " + + "JOIN FETCH main.developer dev " + + "JOIN FETCH main.certificationBody cb " + + "LEFT JOIN FETCH cb.address "; + + List entities = entityManager + .createQuery(hql, DeveloperCertificationBodyMapEntity.class) + .getResultList(); + + Map> map = new HashMap>(); + + entities.forEach(e -> { + if (!map.containsKey(e.getDeveloperId())) { + map.put(e.getDeveloperId(), new ArrayList()); + } + map.get(e.getDeveloperId()).add(e.getCertificationBody().toDomain()); + }); + return map; + } } 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 40626336b3..dabb9428fd 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 @@ -7,6 +7,7 @@ import org.springframework.stereotype.Component; import gov.healthit.chpl.developer.search.DeveloperSearchResult; +import gov.healthit.chpl.report.attestation.AttestationReportService; import gov.healthit.chpl.report.criteriaattribute.StandardListingReport; import gov.healthit.chpl.report.criteriaattribute.StandardReport; import gov.healthit.chpl.report.criteriaattribute.StandardReportService; @@ -30,6 +31,7 @@ import gov.healthit.chpl.report.surveillance.NonconformityCounts; import gov.healthit.chpl.report.surveillance.SurveillanceActivityCounts; import gov.healthit.chpl.report.surveillance.SurveillanceReportsService; +import gov.healthit.chpl.scheduler.job.report.attestation.AttestationReport; import gov.healthit.chpl.scheduler.job.summarystatistics.data.CertificationBodyStatistic; import gov.healthit.chpl.search.domain.ListingSearchResult; import lombok.Synchronized; @@ -49,13 +51,15 @@ public class ReportDataManager { private ServiceBaseUrlListReportService serviceBaseUrlListReportService; private StandardReportService standardReportService; private DirectReviewReportsService directReviewReportsService; + private AttestationReportService attestationReportService; private ReportMetadataDAO reportMetadataDAO; @Autowired public ReportDataManager(CriteriaMigrationReportService criteriaMigrationReportService, DeveloperReportsService developerReportsService, SurveillanceReportsService surveillanceReportsService, ProductReportsService productReportsService, ListingReportsService listingReportsService, TestToolReportService testToolReportService, DirectReviewReportsService directReviewReportsService, ReportMetadataDAO reportMetadataDAO, - ServiceBaseUrlListReportService serviceBaseUrlListReportService, StandardReportService standardReportService) { + ServiceBaseUrlListReportService serviceBaseUrlListReportService, AttestationReportService attestationReportService, + StandardReportService standardReportService) { this.criteriaMigrationReportService = criteriaMigrationReportService; this.developerReportsService = developerReportsService; this.surveillanceReportsService = surveillanceReportsService; @@ -65,6 +69,7 @@ public ReportDataManager(CriteriaMigrationReportService criteriaMigrationReportS this.serviceBaseUrlListReportService = serviceBaseUrlListReportService; this.standardReportService = standardReportService; this.directReviewReportsService = directReviewReportsService; + this.attestationReportService = attestationReportService; this.reportMetadataDAO = reportMetadataDAO; } @@ -266,4 +271,10 @@ public List getStandardListingReports() { public DirectReviewCounts getDirectReviewCounts() { return directReviewReportsService.getDirectReviewCounts(); } + + @Synchronized("lock") + public List getAttestationReports() { + return attestationReportService.getAttestationReports(); + } + } diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/attestation/AttestationReportService.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/attestation/AttestationReportService.java new file mode 100644 index 0000000000..94d67bb5d0 --- /dev/null +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/report/attestation/AttestationReportService.java @@ -0,0 +1,30 @@ +package gov.healthit.chpl.report.attestation; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import gov.healthit.chpl.attestation.manager.AttestationPeriodService; +import gov.healthit.chpl.scheduler.job.report.attestation.AttestationReport; +import gov.healthit.chpl.scheduler.job.report.attestation.AttestationReportDAO; + +@Component +public class AttestationReportService { + + private AttestationReportDAO attestationReportDAO; + private AttestationPeriodService attestationPeriodService; + + @Autowired + public AttestationReportService(AttestationReportDAO attestationReportDAO, AttestationPeriodService attestationPeriodService) { + this.attestationReportDAO = attestationReportDAO; + this.attestationPeriodService = attestationPeriodService; + } + + @Transactional + public List getAttestationReports() { + return attestationReportDAO.getAttestationReportByAttestationPeriod( + attestationPeriodService.getMostRecentPastAttestationPeriod()); + } +} diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/report/attestation/AttestationReport.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/report/attestation/AttestationReport.java new file mode 100644 index 0000000000..3ab7cc3895 --- /dev/null +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/report/attestation/AttestationReport.java @@ -0,0 +1,41 @@ +package gov.healthit.chpl.scheduler.job.report.attestation; + +import java.time.LocalDate; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +import gov.healthit.chpl.attestation.domain.AttestationPeriod; +import gov.healthit.chpl.domain.CertificationBody; +import gov.healthit.chpl.util.LocalDateDeserializer; +import gov.healthit.chpl.util.LocalDateSerializer; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class AttestationReport { + private Long id; + + @JsonDeserialize(using = LocalDateDeserializer.class) + @JsonSerialize(using = LocalDateSerializer.class) + private LocalDate reportDate; + + private CertificationBody certificationBody; + private AttestationPeriod attestationPeriod; + + @Builder.Default + private Long developerCount = 0L; + + @Builder.Default + private Long approvedCount = 0L; + + @Builder.Default + private Long pendingAcbActionCount = 0L; + + @Builder.Default + private Long pendingDeveloperActionCount = 0L; + + @Builder.Default + private Long noSubmissionCount = 0L; +} diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/report/attestation/AttestationReportCreatorJob.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/report/attestation/AttestationReportCreatorJob.java new file mode 100644 index 0000000000..c0ca1f816b --- /dev/null +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/report/attestation/AttestationReportCreatorJob.java @@ -0,0 +1,197 @@ +package gov.healthit.chpl.scheduler.job.report.attestation; + +import java.time.LocalDate; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.tuple.Pair; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.orm.jpa.JpaTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionTemplate; +import org.springframework.web.context.support.SpringBeanAutowiringSupport; + +import gov.healthit.chpl.attestation.domain.AttestationPeriod; +import gov.healthit.chpl.attestation.manager.AttestationManager; +import gov.healthit.chpl.attestation.manager.AttestationPeriodService; +import gov.healthit.chpl.attestation.service.AttestationCertificationBodyService; +import gov.healthit.chpl.changerequest.dao.ChangeRequestAttestationDAO; +import gov.healthit.chpl.changerequest.domain.ChangeRequest; +import gov.healthit.chpl.changerequest.manager.ChangeRequestManager; +import gov.healthit.chpl.domain.CertificationBody; +import gov.healthit.chpl.domain.Developer; +import gov.healthit.chpl.manager.CertificationBodyManager; +import gov.healthit.chpl.scheduler.job.QuartzJob; +import gov.healthit.chpl.scheduler.job.developer.attestation.DeveloperAttestationPeriodCalculator; +import gov.healthit.chpl.util.DateUtil; +import lombok.extern.log4j.Log4j2; + +@Log4j2(topic = "attestationReportCreatorJobLogger") +public class AttestationReportCreatorJob extends QuartzJob { + + @Autowired + private JpaTransactionManager txManager; + + @Autowired + private Environment env; + + @Autowired + private AttestationPeriodService attestationPeriodService; + + @Autowired + private AttestationManager attestationManager; + + @Autowired + private DeveloperAttestationPeriodCalculator developerAttestationPeriodCalculator; + + @Autowired + private CertificationBodyManager certificationBodyManager; + + @Autowired + private AttestationReportDAO attestationReportDAO; + + @Autowired + private ChangeRequestAttestationDAO changeRequestAttestationDAO; + + @Autowired + private ChangeRequestManager changeRequestManager; + + @Autowired + private AttestationCertificationBodyService attestationCertificationBodyService; + + + + @Override + public void execute(JobExecutionContext context) throws JobExecutionException { + SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); + + LOGGER.info("********* Starting Attestation Report Creator job. *********"); + // We need to manually create a transaction in this case because of how + // AOP works. When a method is annotated with @Transactional, the transaction + // wrapper is only added if the object's proxy is called. The object's proxy is + // not called when the method is called from within this class. The object's + // proxy is called when the method is public and is called from a different + // object. + // https://stackoverflow.com/questions/3037006/starting-new-transaction-in-spring-bean + TransactionTemplate txTemplate = new TransactionTemplate(txManager); + txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + txTemplate.execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(TransactionStatus status) { + + try { + if (inSubmissionPlusApprovalPeriod()) { + if (!CollectionUtils.isEmpty(attestationReportDAO.getAttestationReportByDate(LocalDate.now()))) { + attestationReportDAO.deleteAttestationReportByDate(LocalDate.now()); + } + + AttestationPeriod mostRecentPastAttestationPeriod = attestationPeriodService.getMostRecentPastAttestationPeriod(); + Map attestationReportsByAcbId = new HashMap(); + List activeAcbs = certificationBodyManager.getAllActive(); + List applicableDevelopers = getDevelopersActiveListingsDuringMostRecentPastAttestationPeriod(); + + applicableDevelopers.forEach(developer -> { + LOGGER.info("Processing Developer: {} ({})", developer.getName(), developer.getId()); + try { + + ChangeRequest cr = getMostRecentChangeRequest(developer, mostRecentPastAttestationPeriod); + + activeAcbs.forEach(acb -> { + if (isDeveloperManagedByAcb(developer, acb, mostRecentPastAttestationPeriod)) { + if (!attestationReportsByAcbId.containsKey(acb.getId())) { + attestationReportsByAcbId.put(acb.getId(), + AttestationReport.builder() + .attestationPeriod(mostRecentPastAttestationPeriod) + .certificationBody(acb) + .reportDate(LocalDate.now()) + .build()); + } + AttestationReport report = attestationReportsByAcbId.get(acb.getId()); + report.setDeveloperCount(report.getDeveloperCount() + 1); + + updateCountsBasedOnChangeRequestStatus(cr, report); + } + }); + } catch (Exception e) { + LOGGER.error("Could not collect Developer Attestation Report data for Developer: {} ", developer.getName(), e); + } + }); + + attestationReportsByAcbId.entrySet().forEach(entry -> attestationReportDAO.insert(entry.getValue())); + + } else { + LOGGER.info("Not within submission plus approval window"); + } + } catch (Exception e) { + LOGGER.error(e); + } + } + + private void updateCountsBasedOnChangeRequestStatus(ChangeRequest cr, AttestationReport report) { + if (cr == null) { + report.setNoSubmissionCount(report.getNoSubmissionCount() + 1); + } else { + switch (cr.getCurrentStatus().getChangeRequestStatusType().getName()) { + case "Accepted": + report.setApprovedCount(report.getApprovedCount() + 1); + break; + case "Pending Developer Action": + report.setPendingDeveloperActionCount(report.getPendingDeveloperActionCount() + 1); + break; + case "Pending ONC-ACB Action": + report.setPendingAcbActionCount(report.getPendingAcbActionCount() + 1); + break; + default: + break; + } + } + } + }); + LOGGER.info("********* Completed Attestation Report Creator job. *********"); + } + + private boolean inSubmissionPlusApprovalPeriod() { + AttestationPeriod attestationPeriod = attestationPeriodService.getMostRecentPastAttestationPeriod(); + return DateUtil.isDateBetweenInclusive( + Pair.of(attestationPeriod.getSubmissionStart(), attestationPeriod.getSubmissionEnd().plusDays(getDaysInApprovalPeriod())), + LocalDate.now()); + } + + private List getDevelopersActiveListingsDuringMostRecentPastAttestationPeriod() { + AttestationPeriod mostRecentPastPeriod = attestationManager.getMostRecentPastAttestationPeriod(); + return developerAttestationPeriodCalculator.getDevelopersWithActiveListingsDuringAttestationPeriod(mostRecentPastPeriod, LOGGER); + } + + private ChangeRequest getMostRecentChangeRequest(Developer developer, AttestationPeriod period) { + Long crId = changeRequestAttestationDAO.getIdOfMostRecentAttestationChangeRequest(developer.getId(), period.getId()); + if (crId == null) { + LOGGER.warn("No change request was found for developer " + developer.getId() + " and attestation period " + period.getId()); + return null; + } + ChangeRequest changeRequest = null; + try { + changeRequest = changeRequestManager.getChangeRequest(crId); + } catch (Exception ex) { + LOGGER.error("Error getting change request with ID " + crId, ex); + } + return changeRequest; + } + + private Boolean isDeveloperManagedByAcb(Developer developer, CertificationBody certificationBody, AttestationPeriod attestationPeriod) { + return attestationCertificationBodyService.getAssociatedCertificationBodies(developer.getId(), attestationPeriod.getId()).stream() + .filter(acb -> acb.getId().equals(certificationBody.getId())) + .findAny() + .isPresent(); + } + + private Integer getDaysInApprovalPeriod() { + return Integer.valueOf(env.getProperty("attestationApprovalWindowInDays")); + } +} diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/report/attestation/AttestationReportDAO.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/report/attestation/AttestationReportDAO.java new file mode 100644 index 0000000000..42ae0f8fe6 --- /dev/null +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/report/attestation/AttestationReportDAO.java @@ -0,0 +1,66 @@ +package gov.healthit.chpl.scheduler.job.report.attestation; + +import java.time.LocalDate; +import java.util.List; + +import org.springframework.stereotype.Component; + +import gov.healthit.chpl.attestation.domain.AttestationPeriod; +import gov.healthit.chpl.attestation.entity.AttestationPeriodEntity; +import gov.healthit.chpl.dao.impl.BaseDAOImpl; +import gov.healthit.chpl.entity.CertificationBodyEntity; +import jakarta.persistence.Query; + +@Component +public class AttestationReportDAO extends BaseDAOImpl { + + public void insert(AttestationReport attestationReport) { + create(AttestationReportEntity.builder() + .approvedCount(attestationReport.getApprovedCount()) + .reportDate(attestationReport.getReportDate()) + .attestationPeriod(AttestationPeriodEntity.builder() + .id(attestationReport.getAttestationPeriod().getId()) + .build()) + .certificationBody(CertificationBodyEntity.builder() + .id(attestationReport.getCertificationBody().getId()) + .build()) + .developerCount(attestationReport.getDeveloperCount()) + .noSubmissionCount(attestationReport.getNoSubmissionCount()) + .pendingAcbActionCount(attestationReport.getPendingAcbActionCount()) + .pendingDeveloperActionCount(attestationReport.getPendingDeveloperActionCount()) + .build()); + } + + public List getAttestationReportByDate(LocalDate date) { + return getEntitiesByDate(date).stream() + .map(entity -> entity.toDomain()) + .toList(); + } + + public List getAttestationReportByAttestationPeriod(AttestationPeriod period) { + return getEntitiesByAttestationPeriod(period).stream() + .map(entity -> entity.toDomain()) + .toList(); + } + + public void deleteAttestationReportByDate(LocalDate date) { + getEntitiesByDate(date).forEach(entity -> { + entity.setDeleted(true); + update(entity); + }); + } + + private List getEntitiesByDate(LocalDate date) { + Query query = entityManager.createQuery( + "from AttestationReportEntity where (NOT deleted = true) and reportDate = :date", AttestationReportEntity.class); + query.setParameter("date", date); + return query.getResultList(); + } + + private List getEntitiesByAttestationPeriod(AttestationPeriod period) { + Query query = entityManager.createQuery( + "from AttestationReportEntity where (NOT deleted = true) and attestationPeriod.id = :attestationPeriodId", AttestationReportEntity.class); + query.setParameter("attestationPeriodId", period.getId()); + return query.getResultList(); + } +} diff --git a/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/report/attestation/AttestationReportEntity.java b/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/report/attestation/AttestationReportEntity.java new file mode 100644 index 0000000000..cd38ec3748 --- /dev/null +++ b/chpl/chpl-service/src/main/java/gov/healthit/chpl/scheduler/job/report/attestation/AttestationReportEntity.java @@ -0,0 +1,80 @@ +package gov.healthit.chpl.scheduler.job.report.attestation; + +import java.time.LocalDate; + +import gov.healthit.chpl.attestation.entity.AttestationPeriodEntity; +import gov.healthit.chpl.entity.CertificationBodyEntity; +import gov.healthit.chpl.entity.EntityAudit; +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 = "attestation_report") +public class AttestationReportEntity extends EntityAudit { + private static final long serialVersionUID = -3139285302653689705L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Column(name = "report_date") + private LocalDate reportDate; + + @OneToOne(optional = true, fetch = FetchType.LAZY) + @JoinColumn(name = "attestation_period_id") + private AttestationPeriodEntity attestationPeriod; + + @OneToOne(optional = true, fetch = FetchType.LAZY) + @JoinColumn(name = "certification_body_id") + private CertificationBodyEntity certificationBody; + + @Column(name = "developer_count") + private Long developerCount; + + @Column(name = "approved_count") + private Long approvedCount; + + @Column(name = "pending_acb_action_count") + private Long pendingAcbActionCount; + + @Column(name = "pending_developer_action_count") + private Long pendingDeveloperActionCount; + + @Column(name = "no_submission_count") + private Long noSubmissionCount; + + public AttestationReport toDomain() { + return AttestationReport.builder() + .id(id) + .reportDate(reportDate) + .attestationPeriod(attestationPeriod.toDomain()) + .certificationBody(certificationBody.toDomain()) + .developerCount(developerCount) + .approvedCount(approvedCount) + .pendingAcbActionCount(pendingAcbActionCount) + .pendingDeveloperActionCount(pendingDeveloperActionCount) + .noSubmissionCount(noSubmissionCount) + .build(); + } + +}