Skip to content

Commit

Permalink
Merge pull request #1035 from bcgov/feature/EDX-2604
Browse files Browse the repository at this point in the history
download sped report by dis and by dis per school
  • Loading branch information
arcshiftsolutions authored Aug 13, 2024
2 parents 1e802b6 + 9c06375 commit c9e2c52
Show file tree
Hide file tree
Showing 10 changed files with 1,271 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public enum ReportTypeCode {
ELL_HEADCOUNT("ELL_HEADCOUNT"),
DIS_REFUGEE_HEADCOUNT_PER_SCHOOL("DIS_REFUGEE_HEADCOUNT_PER_SCHOOL"),
SPECIAL_EDUCATION_HEADCOUNT("SPECIAL_EDUCATION_HEADCOUNT"),
DIS_SPECIAL_EDUCATION_HEADCOUNT("DIS_SPECIAL_EDUCATION_HEADCOUNT"),
DIS_SPECIAL_EDUCATION_HEADCOUNT_PER_SCHOOL("DIS_SPECIAL_EDUCATION_HEADCOUNT_PER_SCHOOL"),
INDIGENOUS_HEADCOUNT("INDIGENOUS_HEADCOUNT"),
BAND_RESIDENCE_HEADCOUNT("BAND_RESIDENCE_HEADCOUNT"),
CAREER_HEADCOUNT("CAREER_HEADCOUNT"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public class ReportGenerationController implements ReportGenerationEndpoint {
private final IndigenousHeadcountReportService indigenousHeadcountReportService;
private final EllHeadcountReportService ellHeadcountReportService;
private final SpecialEdHeadcountReportService specialEdHeadcountReportService;
private final SpecialEdHeadcountPerSchoolReportService specialEdHeadcountPerSchoolReportService;
private final AllStudentLightCollectionGenerateCsvService allStudentLightCollectionGenerateCsvService;
private final BandOfResidenceHeadcountReportService bandOfResidenceHeadcountReportService;
private final GradeEnrollmentHeadcountPerSchoolReportService gradeEnrollmentHeadcountPerSchoolReportService;
Expand Down Expand Up @@ -70,7 +71,9 @@ public DownloadableReportResponse generateSDCReport(UUID collectionID, String re
case BAND_RESIDENCE_HEADCOUNT -> bandOfResidenceHeadcountReportService.generateBandOfResdienceReport(collectionID);
case DIS_REFUGEE_HEADCOUNT_PER_SCHOOL -> refugeeHeadcountPerSchoolReportService.generateRefugeePerSchoolReport(collectionID);
case ELL_HEADCOUNT -> ellHeadcountReportService.generateEllHeadcountReport(collectionID);
case SPECIAL_EDUCATION_HEADCOUNT -> specialEdHeadcountReportService.generateSpecialEdHeadcountReport(collectionID);
case SPECIAL_EDUCATION_HEADCOUNT -> specialEdHeadcountReportService.generateSpecialEdHeadcountReport(collectionID, false);
case DIS_SPECIAL_EDUCATION_HEADCOUNT -> specialEdHeadcountReportService.generateSpecialEdHeadcountReport(collectionID, true);
case DIS_SPECIAL_EDUCATION_HEADCOUNT_PER_SCHOOL -> specialEdHeadcountPerSchoolReportService.generateSpecialEdHeadcountPerSchoolReport(collectionID);
case ALL_STUDENT_SCHOOL_CSV -> allStudentLightCollectionGenerateCsvService.generateFromSdcSchoolCollectionID(collectionID);
case ALL_STUDENT_DIS_CSV -> allStudentLightCollectionGenerateCsvService.generateFromSdcDistrictCollectionID(collectionID);
default -> new DownloadableReportResponse();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,20 @@ protected String convertToReportJSONString(List<T> mappedResults, SdcSchoolColle
return objectWriter.writeValueAsString(mainNode);
}

protected String convertToReportJSONStringDistrict(List<T> mappedResults, SdcDistrictCollectionEntity sdcDistrictCollection) throws JsonProcessingException {
HeadcountNode mainNode = new HeadcountNode();
HeadcountReportNode reportNode = new HeadcountReportNode();
setReportTombstoneValuesDis(sdcDistrictCollection, reportNode);

var nodeMap = generateNodeMap(false);

mappedResults.forEach(result -> setValueForGrade(nodeMap, result));

reportNode.setPrograms(nodeMap.values().stream().sorted(Comparator.comparing(o -> Integer.parseInt(o.getSequence()))).toList());
mainNode.setReport(reportNode);
return objectWriter.writeValueAsString(mainNode);
}

protected District validateAndReturnDistrict(SchoolTombstone schoolTombstone){
var district = restUtils.getDistrictByDistrictID(schoolTombstone.getDistrictId());
if(district.isEmpty()){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,7 @@
import ca.bc.gov.educ.studentdatacollection.api.struct.v1.headcounts.CareerHeadcountResult;
import ca.bc.gov.educ.studentdatacollection.api.struct.v1.reports.DownloadableReportResponse;
import ca.bc.gov.educ.studentdatacollection.api.struct.v1.reports.HeadcountChildNode;
import ca.bc.gov.educ.studentdatacollection.api.struct.v1.reports.HeadcountNode;
import ca.bc.gov.educ.studentdatacollection.api.struct.v1.reports.HeadcountReportNode;
import com.fasterxml.jackson.core.JsonProcessingException;
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.JRException;
Expand All @@ -39,7 +35,6 @@ public class CareerProgramHeadcountPerSchoolReportService extends BaseReportGene
private final RestUtils restUtils;
private List<CareerHeadcountResult> careerHeadcounts = new ArrayList<>();
private List<SchoolTombstone> allSchoolsTombstones;
private final ObjectWriter objectWriter = new ObjectMapper().writer().withDefaultPrettyPrinter();

public CareerProgramHeadcountPerSchoolReportService(SdcSchoolCollectionRepository sdcSchoolCollectionRepository, SdcSchoolCollectionStudentRepository sdcSchoolCollectionStudentRepository, RestUtils restUtils, SdcDistrictCollectionRepository sdcDistrictCollectionRepository, RestUtils restUtils1) {
super(restUtils, sdcSchoolCollectionRepository);
Expand Down Expand Up @@ -74,27 +69,13 @@ public DownloadableReportResponse generateCareerProgramHeadcountPerSchoolReport(

careerHeadcounts = sdcSchoolCollectionStudentRepository.getCareerHeadcountsBySchoolIdAndBySdcDistrictCollectionId(sdcDistrictCollectionEntity.getSdcDistrictCollectionID());
this.allSchoolsTombstones = getAllSchoolTombstones(collectionID);
return generateJasperReport(convertToCareerProgramReportJSONStringDistrict(careerHeadcounts, sdcDistrictCollectionEntity), careerProgramHeadcountPerSchoolReport, ReportTypeCode.DIS_CAREER_HEADCOUNT_PER_SCHOOL);
return generateJasperReport(convertToReportJSONStringDistrict(careerHeadcounts, sdcDistrictCollectionEntity), careerProgramHeadcountPerSchoolReport, ReportTypeCode.DIS_CAREER_HEADCOUNT_PER_SCHOOL);
} catch (JsonProcessingException e) {
log.error("Exception occurred while writing PDF report for grade enrollment dis :: " + e.getMessage());
throw new StudentDataCollectionAPIRuntimeException("Exception occurred while writing PDF report for grade enrollment dis :: " + e.getMessage());
}
}

private String convertToCareerProgramReportJSONStringDistrict(List<CareerHeadcountResult> mappedResults, SdcDistrictCollectionEntity sdcDistrictCollection) throws JsonProcessingException {
HeadcountNode mainNode = new HeadcountNode();
HeadcountReportNode reportNode = new HeadcountReportNode();
setReportTombstoneValuesDis(sdcDistrictCollection, reportNode);

var nodeMap = generateNodeMap(false);

mappedResults.forEach(result -> setValueForGrade(nodeMap, result));

reportNode.setPrograms(nodeMap.values().stream().sorted(Comparator.comparing(o -> Integer.parseInt(o.getSequence()))).toList());
mainNode.setReport(reportNode);
return objectWriter.writeValueAsString(mainNode);
}

public HashMap<String, HeadcountChildNode> generateNodeMap(boolean includeKH){
HashMap<String, HeadcountChildNode> nodeMap = new HashMap<>();
Set<String> includedSchoolIDs = new HashSet<>();
Expand Down Expand Up @@ -160,10 +141,6 @@ public void setValueForGrade(HashMap<String, HeadcountChildNode> nodeMap, Career
nodeMap.get(schoolID + "all").setValueForGrade(code, gradeResult.getAllTotal());
}

if (nodeMap.containsKey(schoolID + "all")) {
nodeMap.get(schoolID + "all").setValueForGrade(code, gradeResult.getAllTotal());
}

if (nodeMap.containsKey(schoolID + "Heading")) {
nodeMap.get(schoolID + "Heading").setAllValuesToNull();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,7 @@
import ca.bc.gov.educ.studentdatacollection.api.struct.v1.headcounts.CareerHeadcountResult;
import ca.bc.gov.educ.studentdatacollection.api.struct.v1.reports.DownloadableReportResponse;
import ca.bc.gov.educ.studentdatacollection.api.struct.v1.reports.HeadcountChildNode;
import ca.bc.gov.educ.studentdatacollection.api.struct.v1.reports.HeadcountNode;
import ca.bc.gov.educ.studentdatacollection.api.struct.v1.reports.HeadcountReportNode;
import com.fasterxml.jackson.core.JsonProcessingException;
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.JRException;
Expand All @@ -37,7 +33,6 @@ public class CareerProgramHeadcountReportService extends BaseReportGenerationSer
private final SdcDistrictCollectionRepository sdcDistrictCollectionRepository;
private final SdcSchoolCollectionStudentRepository sdcSchoolCollectionStudentRepository;
private JasperReport careerProgramHeadcountReport;
private final ObjectWriter objectWriter = new ObjectMapper().writer().withDefaultPrettyPrinter();

public CareerProgramHeadcountReportService(SdcSchoolCollectionRepository sdcSchoolCollectionRepository, SdcSchoolCollectionStudentRepository sdcSchoolCollectionStudentRepository, RestUtils restUtils, SdcDistrictCollectionRepository sdcDistrictCollectionRepository) {
super(restUtils, sdcSchoolCollectionRepository);
Expand Down Expand Up @@ -72,7 +67,7 @@ public DownloadableReportResponse generateCareerProgramHeadcountReport(UUID coll
new EntityNotFoundException(SdcDistrictCollectionEntity.class, "CollectionId", collectionID.toString()));

List<CareerHeadcountResult> careerHeadcounts = sdcSchoolCollectionStudentRepository.getCareerHeadcountsBySdcDistrictCollectionId(sdcDistrictCollectionEntity.getSdcDistrictCollectionID());
return generateJasperReport(convertToCareerProgramReportJSONStringDistrict(careerHeadcounts, sdcDistrictCollectionEntity), careerProgramHeadcountReport, ReportTypeCode.DIS_CAREER_HEADCOUNT);
return generateJasperReport(convertToReportJSONStringDistrict(careerHeadcounts, sdcDistrictCollectionEntity), careerProgramHeadcountReport, ReportTypeCode.DIS_CAREER_HEADCOUNT);
} catch (JsonProcessingException e) {
log.error("Exception occurred while writing PDF report for grade enrollment dis :: " + e.getMessage());
throw new StudentDataCollectionAPIRuntimeException("Exception occurred while writing PDF report for grade enrollment dis :: " + e.getMessage());
Expand All @@ -92,20 +87,6 @@ public DownloadableReportResponse generateCareerProgramHeadcountReport(UUID coll
}
}

private String convertToCareerProgramReportJSONStringDistrict(List<CareerHeadcountResult> mappedResults, SdcDistrictCollectionEntity sdcDistrictCollection) throws JsonProcessingException {
HeadcountNode mainNode = new HeadcountNode();
HeadcountReportNode reportNode = new HeadcountReportNode();
setReportTombstoneValuesDis(sdcDistrictCollection, reportNode);

var nodeMap = generateNodeMap(false);

mappedResults.forEach(result -> setValueForGrade(nodeMap, result));

reportNode.setPrograms(nodeMap.values().stream().sorted(Comparator.comparing(o -> Integer.parseInt(o.getSequence()))).toList());
mainNode.setReport(reportNode);
return objectWriter.writeValueAsString(mainNode);
}

public HashMap<String, HeadcountChildNode> generateNodeMap(boolean includeKH){
HashMap<String, HeadcountChildNode> nodeMap = new HashMap<>();
addValuesForSectionToMap(nodeMap, "careerPrep", "Career Preparation", "00");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package ca.bc.gov.educ.studentdatacollection.api.reports;

import ca.bc.gov.educ.studentdatacollection.api.constants.v1.ReportTypeCode;
import ca.bc.gov.educ.studentdatacollection.api.constants.v1.SchoolGradeCodes;
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.model.v1.SdcDistrictCollectionEntity;
import ca.bc.gov.educ.studentdatacollection.api.properties.ApplicationProperties;
import ca.bc.gov.educ.studentdatacollection.api.repository.v1.SdcDistrictCollectionRepository;
import ca.bc.gov.educ.studentdatacollection.api.repository.v1.SdcSchoolCollectionRepository;
import ca.bc.gov.educ.studentdatacollection.api.repository.v1.SdcSchoolCollectionStudentRepository;
import ca.bc.gov.educ.studentdatacollection.api.rest.RestUtils;
import ca.bc.gov.educ.studentdatacollection.api.struct.external.institute.v1.SchoolTombstone;
import ca.bc.gov.educ.studentdatacollection.api.struct.v1.headcounts.SpecialEdHeadcountResult;
import ca.bc.gov.educ.studentdatacollection.api.struct.v1.reports.DownloadableReportResponse;
import ca.bc.gov.educ.studentdatacollection.api.struct.v1.reports.HeadcountChildNode;
import com.fasterxml.jackson.core.JsonProcessingException;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperReport;
import org.springframework.stereotype.Service;

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

@Service
@Slf4j
public class SpecialEdHeadcountPerSchoolReportService extends BaseReportGenerationService<SpecialEdHeadcountResult> {

private final SdcDistrictCollectionRepository sdcDistrictCollectionRepository;
private final SdcSchoolCollectionStudentRepository sdcSchoolCollectionStudentRepository;
private JasperReport specialEdHeadcountPerSchoolReport;
private final RestUtils restUtils;
private List<SpecialEdHeadcountResult> spedHeadcounts = new ArrayList<>();
private List<SchoolTombstone> allSchoolsTombstones;

public SpecialEdHeadcountPerSchoolReportService(SdcDistrictCollectionRepository sdcDistrictCollectionRepository, SdcSchoolCollectionStudentRepository sdcSchoolCollectionStudentRepository, RestUtils restUtils, SdcSchoolCollectionRepository sdcSchoolCollectionRepository, RestUtils restUtils1) {
super(restUtils, sdcSchoolCollectionRepository);

this.sdcDistrictCollectionRepository = sdcDistrictCollectionRepository;
this.sdcSchoolCollectionStudentRepository = sdcSchoolCollectionStudentRepository;
this.restUtils = restUtils1;
}

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

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

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

public DownloadableReportResponse generateSpecialEdHeadcountPerSchoolReport(UUID collectionID) {
try {
Optional<SdcDistrictCollectionEntity> sdcDistrictCollectionEntityOptional = sdcDistrictCollectionRepository.findById(collectionID);
SdcDistrictCollectionEntity sdcDistrictCollectionEntity = sdcDistrictCollectionEntityOptional.orElseThrow(() ->
new EntityNotFoundException(SdcDistrictCollectionEntity.class, "CollectionId", collectionID.toString()));

spedHeadcounts = sdcSchoolCollectionStudentRepository.getSpecialEdHeadcountsBySchoolIdAndBySdcDistrictCollectionId(sdcDistrictCollectionEntity.getSdcDistrictCollectionID());
this.allSchoolsTombstones = getAllSchoolTombstones(collectionID);
return generateJasperReport(convertToReportJSONStringDistrict(spedHeadcounts, sdcDistrictCollectionEntity), specialEdHeadcountPerSchoolReport, ReportTypeCode.DIS_SPECIAL_EDUCATION_HEADCOUNT_PER_SCHOOL);
} catch (JsonProcessingException e) {
log.error("Exception occurred while writing PDF report for inclusive education dis per school :: " + e.getMessage());
throw new StudentDataCollectionAPIRuntimeException("Exception occurred while writing PDF report for inclusive education dis per school :: " + e.getMessage());
}
}

public HashMap<String, HeadcountChildNode> generateNodeMap(boolean includeKH) {
HashMap<String, HeadcountChildNode> nodeMap = new HashMap<>();
Set<String> includedSchoolIDs = new HashSet<>();

int sequencePrefix = 10;
if (!spedHeadcounts.isEmpty()) {
for (SpecialEdHeadcountResult result : spedHeadcounts) {
String schoolID = result.getSchoolID();
Optional<SchoolTombstone> schoolOptional = restUtils.getSchoolBySchoolID(schoolID);
int finalSequencePrefix = sequencePrefix;
schoolOptional.ifPresent(school -> {
includedSchoolIDs.add(school.getSchoolId());
String schoolTitle = school.getMincode() + " - " + school.getDisplayName();
addValuesForSectionToMap(nodeMap, schoolID, schoolTitle, String.valueOf(finalSequencePrefix));
});
sequencePrefix += 10;
}
}

for (SchoolTombstone school : allSchoolsTombstones) {
if (!includedSchoolIDs.contains(school.getSchoolId())) {
String schoolTitle = school.getMincode() + " - " + school.getDisplayName();
addValuesForSectionToMap(nodeMap, school.getSchoolId(), schoolTitle, String.valueOf(sequencePrefix));
sequencePrefix += 10;
}
}

return nodeMap;
}

private void addValuesForSectionToMap(HashMap<String, HeadcountChildNode> nodeMap, String sectionPrefix, String sectionTitle, String sequencePrefix){
nodeMap.put(sectionPrefix + "Heading", new HeadcountChildNode(sectionTitle, "true", sequencePrefix + "0", false));
nodeMap.put(sectionPrefix + "level1", new HeadcountChildNode("Level 1", FALSE, sequencePrefix + "1", false));
nodeMap.put(sectionPrefix + "level2", new HeadcountChildNode("Level 2", FALSE, sequencePrefix + "2", false));
nodeMap.put(sectionPrefix + "level3", new HeadcountChildNode("Level 3", FALSE, sequencePrefix + "3", false));
nodeMap.put(sectionPrefix + "other", new HeadcountChildNode("Other", FALSE, sequencePrefix + "4", false));
nodeMap.put(sectionPrefix + "all", new HeadcountChildNode("All Levels & Categories", FALSE, sequencePrefix + "5", false));
}

public void setValueForGrade(HashMap<String, HeadcountChildNode> nodeMap, SpecialEdHeadcountResult gradeResult) {
Optional<SchoolGradeCodes> optionalCode = SchoolGradeCodes.findByValue(gradeResult.getEnrolledGradeCode());
var code = optionalCode.orElseThrow(() ->
new EntityNotFoundException(SchoolGradeCodes.class, "Grade Value", gradeResult.getEnrolledGradeCode()));
String schoolID = gradeResult.getSchoolID();

if (nodeMap.containsKey(schoolID + "level1")) {
nodeMap.get(schoolID + "level1").setValueForGrade(code, gradeResult.getLevelOnes());
}

if (nodeMap.containsKey(schoolID + "level2")) {
nodeMap.get(schoolID + "level2").setValueForGrade(code, gradeResult.getLevelTwos());
}

if (nodeMap.containsKey(schoolID + "level3")) {
nodeMap.get(schoolID + "level3").setValueForGrade(code, gradeResult.getLevelThrees());
}

if (nodeMap.containsKey(schoolID + "other")) {
nodeMap.get(schoolID + "other").setValueForGrade(code, gradeResult.getOtherLevels());
}

if (nodeMap.containsKey(schoolID + "all")) {
nodeMap.get(schoolID + "all").setValueForGrade(code, gradeResult.getAllLevels());
}

if (nodeMap.containsKey(schoolID + "Heading")) {
nodeMap.get(schoolID + "Heading").setAllValuesToNull();
}
}
}
Loading

0 comments on commit c9e2c52

Please sign in to comment.