Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
arcshiftsolutions committed Aug 15, 2024
2 parents c81a875 + 3d8d9cc commit 8c90f87
Show file tree
Hide file tree
Showing 24 changed files with 2,921 additions and 126 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package ca.bc.gov.educ.studentdatacollection.api.constants.v1;

import lombok.Getter;

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

@Getter
public enum MinistryReportTypeCode {
SCHOOL_ENROLLMENT_HEADCOUNTS("school-enrollment-headcounts");

private final String code;
MinistryReportTypeCode(String code) { this.code = code; }

public static Optional<MinistryReportTypeCode> 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 @@ -14,11 +14,15 @@ public enum ReportTypeCode {
DIS_GRADE_ENROLLMENT_HEADCOUNT("DIS_GRADE_ENROLLMENT_HEADCOUNT"),
DIS_GRADE_ENROLLMENT_HEADCOUNT_PER_SCHOOL("DIS_GRADE_ENROLLMENT_HEADCOUNT_PER_SCHOOL"),
ELL_HEADCOUNT("ELL_HEADCOUNT"),
DIS_ELL_HEADCOUNT("DIS_ELL_HEADCOUNT"),
DIS_ELL_HEADCOUNT_PER_SCHOOL("DIS_ELL_HEADCOUNT_PER_SCHOOL"),
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"),
DIS_INDIGENOUS_HEADCOUNT("DIS_INDIGENOUS_HEADCOUNT"),
DIS_INDIGENOUS_HEADCOUNT_PER_SCHOOL("DIS_INDIGENOUS_HEADCOUNT_PER_SCHOOL"),
BAND_RESIDENCE_HEADCOUNT("BAND_RESIDENCE_HEADCOUNT"),
CAREER_HEADCOUNT("CAREER_HEADCOUNT"),
FRENCH_HEADCOUNT("FRENCH_HEADCOUNT"),
Expand Down
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_DISTRICT_COLLECTION="/api/v1/student-data-collection/sdcDistrictCollection";
public static final String BASE_DISTRICT_HEADCOUNTS = "/api/v1/student-data-collection/headcounts";
public static final String BASE_MINISTRY_HEADCOUNTS = "/api/v1/student-data-collection/ministryHeadcounts";
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";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package ca.bc.gov.educ.studentdatacollection.api.constants.v1.ministryreports;

import lombok.Getter;

@Getter
public enum SchoolEnrolmentHeader {

SCHOOL_ENROLMENT_COLLECTION("School Enrolment Collection"),
SCHOOL_YEAR("School Year"),
DISTRICT_NUMBER("District Number"),
SCHOOL_NUMBER("School Number"),
SCHOOL_NAME("School Name"),
FACILITY_TYPE("Facility Type"),
SCHOOL_CATEGORY("School Category"),
GRADE_RANGE("Grade Range"),
REPORT_DATE("Report Date"),
KIND_HT_COUNT("Kind(H/T) Count"),
KIND_FT_COUNT("Kind(F/T) Count"),
GRADE_01_COUNT("Grade 1 Count"),
GRADE_02_COUNT("Grade 2 Count"),
GRADE_03_COUNT("Grade 3 Count"),
GRADE_04_COUNT("Grade 4 Count"),
GRADE_05_COUNT("Grade 5 Count"),
GRADE_06_COUNT("Grade 6 Count"),
GRADE_07_COUNT("Grade 7 Count"),
GRADE_08_COUNT("Grade 8 Count"),
GRADE_09_COUNT("Grade 9 Count"),
GRADE_10_COUNT("Grade 10 Count"),
GRADE_11_COUNT("Grade 11 Count"),
GRADE_12_COUNT("Grade 12 Count");

private final String code;
SchoolEnrolmentHeader(String code) { this.code = code; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package ca.bc.gov.educ.studentdatacollection.api.controller.v1;

import ca.bc.gov.educ.studentdatacollection.api.constants.v1.MinistryReportTypeCode;
import ca.bc.gov.educ.studentdatacollection.api.endpoint.v1.MinistryHeadcountReports;
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.service.v1.MinistryHeadcountService;
import ca.bc.gov.educ.studentdatacollection.api.struct.v1.headcounts.HeadcountResultsTable;
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 MinistryHeadcountReportsController implements MinistryHeadcountReports {

private final MinistryHeadcountService ministryHeadcountService;

@Override
public HeadcountResultsTable getMinistryHeadcounts(UUID collectionID, String type) {
Optional<MinistryReportTypeCode> code = MinistryReportTypeCode.findByValue(type);

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);
}

return switch(code.get()) {
case SCHOOL_ENROLLMENT_HEADCOUNTS -> ministryHeadcountService.getAllSchoolEnrollmentHeadcounts(collectionID);
default -> new HeadcountResultsTable();
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ public class ReportGenerationController implements ReportGenerationEndpoint {
private final FrenchProgramHeadcountReportService frenchProgramHeadcountReportService;
private final FrenchPerSchoolHeadcountReportService frenchPerSchoolHeadcountReportService;
private final IndigenousHeadcountReportService indigenousHeadcountReportService;
private final IndigenousPerSchoolHeadcountReportService indigenousPerSchoolHeadcountReportService;
private final EllHeadcountReportService ellHeadcountReportService;
private final EllHeadcountPerSchoolReportService ellHeadcountPerSchoolReportService;
private final SpecialEdHeadcountReportService specialEdHeadcountReportService;
private final SpecialEdHeadcountPerSchoolReportService specialEdHeadcountPerSchoolReportService;
private final AllStudentLightCollectionGenerateCsvService allStudentLightCollectionGenerateCsvService;
Expand Down Expand Up @@ -67,10 +69,14 @@ public DownloadableReportResponse generateSDCReport(UUID collectionID, String re
case FRENCH_HEADCOUNT -> frenchProgramHeadcountReportService.generateFrenchProgramHeadcountReport(collectionID, false);
case DIS_FRENCH_HEADCOUNT -> frenchProgramHeadcountReportService.generateFrenchProgramHeadcountReport(collectionID, true);
case DIS_FRENCH_HEADCOUNT_PER_SCHOOL -> frenchPerSchoolHeadcountReportService.generatePerSchoolReport(collectionID);
case INDIGENOUS_HEADCOUNT -> indigenousHeadcountReportService.generateIndigenousHeadcountReport(collectionID);
case INDIGENOUS_HEADCOUNT -> indigenousHeadcountReportService.generateIndigenousHeadcountReport(collectionID, false);
case DIS_INDIGENOUS_HEADCOUNT -> indigenousHeadcountReportService.generateIndigenousHeadcountReport(collectionID, true);
case DIS_INDIGENOUS_HEADCOUNT_PER_SCHOOL -> indigenousPerSchoolHeadcountReportService.generateIndigenousHeadcountPerSchoolReport(collectionID);
case BAND_RESIDENCE_HEADCOUNT -> bandOfResidenceHeadcountReportService.generateBandOfResdienceReport(collectionID);
case DIS_REFUGEE_HEADCOUNT_PER_SCHOOL -> refugeeHeadcountPerSchoolReportService.generateRefugeePerSchoolReport(collectionID);
case ELL_HEADCOUNT -> ellHeadcountReportService.generateEllHeadcountReport(collectionID);
case ELL_HEADCOUNT -> ellHeadcountReportService.generateEllHeadcountReport(collectionID, false);
case DIS_ELL_HEADCOUNT -> ellHeadcountReportService.generateEllHeadcountReport(collectionID, true);
case DIS_ELL_HEADCOUNT_PER_SCHOOL -> ellHeadcountPerSchoolReportService.generateEllHeadcountPerSchoolReport(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);
Expand Down
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 ca.bc.gov.educ.studentdatacollection.api.struct.v1.headcounts.HeadcountResultsTable;
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_MINISTRY_HEADCOUNTS)
public interface MinistryHeadcountReports {

@GetMapping("/{collectionID}/{type}")
@PreAuthorize("hasAuthority('SCOPE_READ_SDC_MINISTRY_REPORTS')")
@Transactional(readOnly = true)
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "BAD REQUEST")})
HeadcountResultsTable getMinistryHeadcounts(@PathVariable UUID collectionID, @PathVariable(name = "type") String type);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
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.EllHeadcountResult;
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 EllHeadcountPerSchoolReportService extends BaseReportGenerationService<EllHeadcountResult> {
protected static final String ALLELL = "allEll";
private final SdcDistrictCollectionRepository sdcDistrictCollectionRepository;
private final SdcSchoolCollectionStudentRepository sdcSchoolCollectionStudentRepository;
private JasperReport ellHeadcountPerSchoolReport;
private final RestUtils restUtils;
private List<EllHeadcountResult> ellHeadcounts = new ArrayList<>();
private List<SchoolTombstone> allSchoolsTombstones;

public EllHeadcountPerSchoolReportService(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");
ellHeadcountPerSchoolReport = JasperCompileManager.compileReport(inputSpecialEdHeadcount);
} catch (JRException e) {
throw new StudentDataCollectionAPIRuntimeException("Compiling Jasper reports has failed :: " + e.getMessage());
}
}

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

ellHeadcounts = sdcSchoolCollectionStudentRepository.getEllHeadcountsByBySchoolIdAndSdcDistrictCollectionId(sdcDistrictCollectionEntity.getSdcDistrictCollectionID());
this.allSchoolsTombstones = getAllSchoolTombstones(collectionID);
return generateJasperReport(convertToReportJSONStringDistrict(ellHeadcounts, sdcDistrictCollectionEntity), ellHeadcountPerSchoolReport, ReportTypeCode.DIS_ELL_HEADCOUNT_PER_SCHOOL);
} catch (JsonProcessingException e) {
log.error("Exception occurred while writing PDF report for ell dis per school :: " + e.getMessage());
throw new StudentDataCollectionAPIRuntimeException("Exception occurred while writing PDF report for ell dis per school :: " + e.getMessage());
}
}

public HashMap<String, HeadcountChildNode> generateNodeMap(boolean includeKH) {
HashMap<String, HeadcountChildNode> nodeMap = new HashMap<>();
Set<String> includedSchoolIDs = new HashSet<>();
addValuesForSectionToMap(nodeMap, ALLELL, "All English Language Learners Headcount for All Schools", "00");

int sequencePrefix = 10;
if (!ellHeadcounts.isEmpty()) {
for (EllHeadcountResult result : ellHeadcounts) {
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) {
if (Objects.equals(sectionPrefix, ALLELL)) {
nodeMap.put(sectionPrefix, new HeadcountChildNode(sectionTitle, "true", sequencePrefix + "0", false, false, false, false));
} else {
nodeMap.put(sectionPrefix + "Heading", new HeadcountChildNode(sectionTitle, "true", sequencePrefix + "0", false));
nodeMap.put(sectionPrefix + "all", new HeadcountChildNode("All English Language Learners", FALSE, sequencePrefix + "1", false));
}
}

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

HeadcountChildNode allEllNode = nodeMap.get(ALLELL);
if (allEllNode.getValueForGrade(code) == null) {
allEllNode.setValueForGrade(code, "0");
}

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

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

int currentTotal = Integer.parseInt(gradeResult.getTotalEllStudents());
int accumulatedTotal = Integer.parseInt(allEllNode.getValueForGrade(code));
allEllNode.setValueForGrade(code, String.valueOf(accumulatedTotal + currentTotal));
}
}
Loading

0 comments on commit 8c90f87

Please sign in to comment.