Skip to content

Commit

Permalink
Merge pull request #460 from bcgov/feature/reportGen
Browse files Browse the repository at this point in the history
Report gen working
  • Loading branch information
mightycox authored Feb 16, 2024
2 parents 7cf9c28 + 942cefb commit 3d896c6
Show file tree
Hide file tree
Showing 14 changed files with 995 additions and 40 deletions.
10 changes: 10 additions & 0 deletions api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,16 @@
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>6.21.0</version>
</dependency>
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports-fonts</artifactId>
<version>6.21.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package ca.bc.gov.educ.studentdatacollection.api.constants.v1;

import lombok.Getter;

import java.util.Arrays;
import java.util.Optional;

/**
* The enum Event outcome.
*/
public enum ReportTypeCode {

GRADE_ENROLLMENT_FTE("GRADE_ENROLLMENT_FTE");

@Getter
private final String code;
ReportTypeCode(String code) {
this.code = code;
}

public static Optional<ReportTypeCode> findByValue(String value) {
return Arrays.stream(values()).filter(e -> Arrays.asList(e.code).contains(value)).findFirst();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ private URL(){
public static final String BASE_URL_COLLECTION="/api/v1/student-data-collection/collection";
public static final String BASE_URL_SCHOOL_COLLECTION="/api/v1/student-data-collection/sdcSchoolCollection";
public static final String BASE_URL_SCHOOL_COLLECTION_STUDENT="/api/v1/student-data-collection/sdcSchoolCollectionStudent";
public static final String BASE_URL_REPORT_GENERATION="/api/v1/student-data-collection/reportGeneration";
public static final String BASE_URL_SCHOOL_FUNDING="/api/v1/student-data-collection/schoolFundingGroup";
public static final String ENROLLED_PROGRAM_CODES="/enrolled-program-codes";
public static final String CAREER_PROGRAM_CODES="/career-program-codes";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package ca.bc.gov.educ.studentdatacollection.api.controller.v1;

import ca.bc.gov.educ.studentdatacollection.api.constants.v1.ReportTypeCode;
import ca.bc.gov.educ.studentdatacollection.api.endpoint.v1.ReportGenerationEndpoint;
import ca.bc.gov.educ.studentdatacollection.api.exception.InvalidPayloadException;
import ca.bc.gov.educ.studentdatacollection.api.exception.errors.ApiError;
import ca.bc.gov.educ.studentdatacollection.api.reports.ReportGenerationService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.util.Optional;
import java.util.UUID;

import static org.springframework.http.HttpStatus.BAD_REQUEST;

@RestController
@Slf4j
@RequiredArgsConstructor
public class ReportGenerationController implements ReportGenerationEndpoint {

private final ReportGenerationService reportGenerationService;

@Override
public byte[] generateSDCReport(UUID collectionID, String reportTypeCode) {
Optional<ReportTypeCode> code = ReportTypeCode.findByValue(reportTypeCode);

if(code.isEmpty()){
ApiError error = ApiError.builder().timestamp(LocalDateTime.now()).message("Payload contains invalid report type code.").status(BAD_REQUEST).build();
throw new InvalidPayloadException(error);
}

switch(code.get()){
case GRADE_ENROLLMENT_FTE:
return reportGenerationService.generateGradeEnrollementFTEReport(collectionID);
}

return new byte[0];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package ca.bc.gov.educ.studentdatacollection.api.endpoint.v1;

import ca.bc.gov.educ.studentdatacollection.api.constants.v1.URL;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.UUID;

@RequestMapping(URL.BASE_URL_REPORT_GENERATION)
public interface ReportGenerationEndpoint {

@GetMapping("/{sdcSchoolCollectionID}/{reportTypeCode}")
@PreAuthorize("hasAuthority('SCOPE_READ_SDC_SCHOOL_COLLECTION')")
@Transactional(readOnly = true)
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "NOT FOUND")})
byte[] generateSDCReport(@PathVariable("sdcSchoolCollectionID") UUID sdcSchoolCollectionID, @PathVariable("reportTypeCode") String reportTypeCode);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package ca.bc.gov.educ.studentdatacollection.api.reports;

import ca.bc.gov.educ.studentdatacollection.api.exception.EntityNotFoundException;
import ca.bc.gov.educ.studentdatacollection.api.exception.StudentDataCollectionAPIRuntimeException;
import ca.bc.gov.educ.studentdatacollection.api.mappers.v1.SdcSchoolCollectionMapper;
import ca.bc.gov.educ.studentdatacollection.api.model.v1.SdcSchoolCollectionEntity;
import ca.bc.gov.educ.studentdatacollection.api.properties.ApplicationProperties;
import ca.bc.gov.educ.studentdatacollection.api.repository.v1.SdcSchoolCollectionRepository;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.query.JsonQueryExecuterFactory;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.*;

@Service
@Slf4j
public class ReportGenerationService {

private final SdcSchoolCollectionRepository sdcSchoolCollectionRepository;
private JasperReport gradeEnrollmentFTEReport;
private ObjectWriter objectWriter = new ObjectMapper().writer().withDefaultPrettyPrinter();

public ReportGenerationService(SdcSchoolCollectionRepository sdcSchoolCollectionRepository) {
this.sdcSchoolCollectionRepository = sdcSchoolCollectionRepository;
}

@PostConstruct
public void init() {
ApplicationProperties.bgTask.execute(this::initialize);
}

private void initialize() {
this.compileJasperReports();
}

private void compileJasperReports(){
try {
InputStream input = getClass().getResourceAsStream("/gradeEnrollmentFTEReport.jrxml");
gradeEnrollmentFTEReport = JasperCompileManager.compileReport(input);
} catch (JRException e) {
throw new StudentDataCollectionAPIRuntimeException("Compiling Jasper reports has failed :: " + e.getMessage());
}
}

public byte[] generateGradeEnrollementFTEReport(UUID collectionID){
try {
Optional<SdcSchoolCollectionEntity> sdcSchoolCollectionEntityOptional = sdcSchoolCollectionRepository.findById(collectionID);
SdcSchoolCollectionEntity sdcSchoolCollectionEntity = sdcSchoolCollectionEntityOptional.orElseThrow(() ->
new EntityNotFoundException(SdcSchoolCollectionEntity.class, "Collection by Id", collectionID.toString()));

Map<String, Object> params = new HashMap<>();
params.put(JsonQueryExecuterFactory.JSON_DATE_PATTERN, "yyyy-MM-dd");
params.put(JsonQueryExecuterFactory.JSON_NUMBER_PATTERN, "#,##0.##");
params.put(JsonQueryExecuterFactory.JSON_LOCALE, Locale.ENGLISH);
params.put(JRParameter.REPORT_LOCALE, Locale.US);
var schoolColl = SdcSchoolCollectionMapper.mapper.toStructure(sdcSchoolCollectionEntity);
String json = "{\"report\": { \"collectionNameAndYear\": \"September 2023 Collection\", \"reportGeneratedDate\": \"Report Date: 2023-10-03\", \"districtNumberAndName\": \"085 - Vancouver Island\", \"schoolMincodeAndName\": \"08585023 - Eagle View Elementary School\", \"grades\": [{ \"code\": \"KF\", \"schoolAgedHeadcount\": \"100\", \"schoolAgedEligibleForFTE\": \"0\", \"schoolAgedFTETotal\": \"100.0000\", \"adultHeadcount\": \"100\", \"adultEligibleForFTE\": \"0\", \"adultFTETotal\": \"100.0000\", \"allStudentHeadcount\": \"90\", \"allStudentEligibleForFTE\": \"10\", \"allStudentFTETotal\": \"90.0000\"},{ \"code\": \"01\", \"schoolAgedHeadcount\": \"100\", \"schoolAgedEligibleForFTE\": \"50\", \"schoolAgedFTETotal\": \"100.0000\", \"adultHeadcount\": \"60\", \"adultEligibleForFTE\": \"5\", \"adultFTETotal\": \"150.0000\", \"allStudentHeadcount\": \"100\", \"allStudentEligibleForFTE\": \"0\", \"allStudentFTETotal\": \"100.0000\", \"totalCountsCode\": \"Total\", \"totalSchoolAgedHeadcount\": \"300\"} ] }}";
// String json = objectWriter.writeValueAsString(schoolColl);
InputStream targetStream = new ByteArrayInputStream(json.getBytes());
params.put(JsonQueryExecuterFactory.JSON_INPUT_STREAM, targetStream);

JasperPrint jasperPrint = JasperFillManager.fillReport(gradeEnrollmentFTEReport, params);
return JasperExportManager.exportReportToPdf(jasperPrint);
} catch (Exception e) {
log.info("Exception occurred while writing PDF report for grade enrollment :: " + e.getMessage());
throw new StudentDataCollectionAPIRuntimeException("Exception occurred while writing PDF report for grade enrollment :: " + e.getMessage());
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package ca.bc.gov.educ.studentdatacollection.api.struct.v1.reports;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@SuppressWarnings("squid:S1700")
public class GradeEnrollementFTENode implements Serializable {
private static final long serialVersionUID = 6118916290604876032L;

private GradeEnrollementFTEReportNode report;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package ca.bc.gov.educ.studentdatacollection.api.struct.v1.reports;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@SuppressWarnings("squid:S1700")
public class GradeEnrollementFTEReportGradesNode implements Serializable {
private static final long serialVersionUID = 6118916290604876032L;

private String code;

private String schoolAgedHeadcount;

private String schoolAgedEligibleForFTE;

private String schoolAgedFTETotal;

private String adultHeadcount;

private String adultEligibleForFTE;

private String adultFTETotal;

private String allStudentHeadcount;

private String allStudentEligibleForFTE;

private String allStudentFTETotal;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package ca.bc.gov.educ.studentdatacollection.api.struct.v1.reports;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@SuppressWarnings("squid:S1700")
public class GradeEnrollementFTEReportNode implements Serializable {
private static final long serialVersionUID = 6118916290604876032L;

private String collectionNameAndYear;

private String reportGeneratedDate;

private String districtNumberAndName;

private String schoolMincodeAndName;

private List<GradeEnrollementFTEReportGradesNode> grades;

}
Loading

0 comments on commit 3d896c6

Please sign in to comment.