Skip to content

Commit

Permalink
PEN Merges enhancement & csv export.
Browse files Browse the repository at this point in the history
  • Loading branch information
sumathi-thirumani committed Dec 2, 2024
1 parent 46d3763 commit d62fc19
Show file tree
Hide file tree
Showing 16 changed files with 423 additions and 88 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ public enum EventOutcome {
STUDENT_REGISTRATION_PUBLISHED,
SAGA_COMPLETED,
STUDENT_ALREADY_EXIST,
MERGE_FOUND
MERGE_FOUND,
STUDENTS_FOUND
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ public enum EventType {
GET_STUDENT_ASSESSMENT_DETAILS,
PUBLISH_STUDENT_REGISTRATION_EVENT,
PUBLISH_STUDENT_REGISTRATION,
GET_OPEN_ASSESSMENT_SESSIONS
GET_OPEN_ASSESSMENT_SESSIONS,
GET_STUDENTS;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ public enum TopicsEnum {
EAS_EVENTS_TOPIC,
PEN_SERVICES_API_TOPIC,
PUBLISH_STUDENT_REGISTRATION_TOPIC,
PUBLISH_STUDENT_REGISTRATION_SAGA_TOPIC
PUBLISH_STUDENT_REGISTRATION_SAGA_TOPIC,
STUDENT_API_TOPIC;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

@Getter
public enum EASReportTypeCode {
ALL_SESSION_REGISTRATIONS("ALL_SESSION_REGISTRATIONS");

ALL_SESSION_REGISTRATIONS("ALL_SESSION_REGISTRATIONS"),
PEN_MERGES("PEN_MERGES");
private final String code;
EASReportTypeCode(String code) { this.code = code; }

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package ca.bc.gov.educ.eas.api.constants.v1.reports;

import lombok.Getter;

@Getter
public enum PenMergesHeader {

CURRENT_PEN("Current PEN"),
MERGED_PEN("Merged PEN");

private final String code;
PenMergesHeader(String code) { this.code = code; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public DownloadableReportResponse getDownloadableReport(UUID sessionID, String t

return switch (code.get()) {
case ALL_SESSION_REGISTRATIONS -> ministryReportsService.generateSessionRegistrationsReport(sessionID);
case PEN_MERGES -> ministryReportsService.generatePenMergesReport();
default -> new DownloadableReportResponse();
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import ca.bc.gov.educ.eas.api.endpoint.v1.StudentMergeEndpoint;
import ca.bc.gov.educ.eas.api.service.v1.StudentMergeService;
import ca.bc.gov.educ.eas.api.struct.v1.StudentMerge;
import ca.bc.gov.educ.eas.api.struct.v1.StudentMergeResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RestController;

Expand All @@ -18,7 +19,7 @@ public StudentMergeController(StudentMergeService studentMergeService){
}

@Override
public List<StudentMerge> getMergedStudentsForDateRange(String createDateStart, String createDateEnd){
public List<StudentMergeResult> getMergedStudentsForDateRange(String createDateStart, String createDateEnd){
return studentMergeService.getMergedStudentsForDateRange(createDateStart, createDateEnd);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package ca.bc.gov.educ.eas.api.endpoint.v1;

import ca.bc.gov.educ.eas.api.constants.v1.URL;
import ca.bc.gov.educ.eas.api.struct.v1.StudentMerge;
import ca.bc.gov.educ.eas.api.struct.v1.StudentMergeResult;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
Expand All @@ -20,6 +20,6 @@ public interface StudentMergeEndpoint {
@PreAuthorize("hasAuthority('SCOPE_READ_EAS_STUDENT')")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
@Tag(name = "PEN Records", description = "Endpoints to retrieve PEN records.")
List<StudentMerge> getMergedStudentsForDateRange(@RequestParam(name = "createDateStart") String createDateStart, @RequestParam(name = "createDateEnd") String createDateEnd) throws JsonProcessingException;
List<StudentMergeResult> getMergedStudentsForDateRange(@RequestParam(name = "createDateStart") String createDateStart, @RequestParam(name = "createDateEnd") String createDateEnd) throws JsonProcessingException;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package ca.bc.gov.educ.eas.api.mappers.v1;

import ca.bc.gov.educ.eas.api.mappers.LocalDateTimeMapper;
import ca.bc.gov.educ.eas.api.mappers.UUIDMapper;
import ca.bc.gov.educ.eas.api.struct.v1.StudentMerge;
import ca.bc.gov.educ.eas.api.struct.v1.StudentMergeResult;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

@Mapper(uses = {UUIDMapper.class, LocalDateTimeMapper.class, AssessmentMapper.class})
public interface StudentMergeMapper {

StudentMergeMapper mapper = Mappers.getMapper(StudentMergeMapper.class);

StudentMergeResult toStructure(StudentMerge studentMerge);
}
22 changes: 22 additions & 0 deletions api/src/main/java/ca/bc/gov/educ/eas/api/rest/RestUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import ca.bc.gov.educ.eas.api.properties.ApplicationProperties;
import ca.bc.gov.educ.eas.api.struct.Event;
import ca.bc.gov.educ.eas.api.struct.external.institute.v1.*;
import ca.bc.gov.educ.eas.api.struct.external.studentapi.v1.Student;
import ca.bc.gov.educ.eas.api.struct.v1.StudentMerge;
import ca.bc.gov.educ.eas.api.util.JsonUtil;
import com.fasterxml.jackson.core.type.TypeReference;
Expand Down Expand Up @@ -348,4 +349,25 @@ public List<StudentMerge> getMergedStudentsForDateRange(UUID correlationID, Stri
throw new EasAPIRuntimeException(ex.getMessage());
}
}

public List<Student> getStudents(UUID correlationID, Set<String> studentIDs) {
try {
final TypeReference<Event> refEventResponse = new TypeReference<>() {};
final TypeReference<List<Student>> refStudentResponse = new TypeReference<>() {};
Object event = Event.builder().sagaId(correlationID).eventType(EventType.GET_STUDENTS).eventPayload(objectMapper.writeValueAsString(studentIDs)).build();
val responseMessage = this.messagePublisher.requestMessage(TopicsEnum.STUDENT_API_TOPIC.toString(), JsonUtil.getJsonBytesFromObject(event)).completeOnTimeout(null, 120, TimeUnit.SECONDS).get();
if (responseMessage == null) {
log.error("Received null response from GET STUDENTS for correlationID: {}", correlationID);
throw new EasAPIRuntimeException(NATS_TIMEOUT + correlationID);
} else {
val eventResponse = objectMapper.readValue(responseMessage.getData(), refEventResponse);
return objectMapper.readValue(eventResponse.getEventPayload(), refStudentResponse);
}

} catch (final Exception ex) {
log.error("Error occurred calling GET STUDENTS service :: " + ex.getMessage());
Thread.currentThread().interrupt();
throw new EasAPIRuntimeException(ex.getMessage());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@


import ca.bc.gov.educ.eas.api.constants.v1.reports.AllStudentRegistrationsHeader;
import ca.bc.gov.educ.eas.api.constants.v1.reports.PenMergesHeader;
import ca.bc.gov.educ.eas.api.constants.v1.reports.EASReportTypeCode;
import ca.bc.gov.educ.eas.api.exception.EasAPIRuntimeException;
import ca.bc.gov.educ.eas.api.exception.EntityNotFoundException;
Expand All @@ -11,18 +12,22 @@
import ca.bc.gov.educ.eas.api.repository.v1.SessionRepository;
import ca.bc.gov.educ.eas.api.rest.RestUtils;
import ca.bc.gov.educ.eas.api.struct.external.institute.v1.SchoolTombstone;
import ca.bc.gov.educ.eas.api.struct.v1.StudentMergeResult;
import ca.bc.gov.educ.eas.api.struct.v1.reports.DownloadableReportResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;


Expand All @@ -32,6 +37,7 @@
public class CSVReportService {
private final SessionRepository sessionRepository;
private final AssessmentStudentRepository assessmentStudentRepository;
private final StudentMergeService studentMergeService;
private final RestUtils restUtils;
private static final String SCHOOL_ID = "schoolID";

Expand Down Expand Up @@ -74,6 +80,40 @@ public DownloadableReportResponse generateSessionRegistrationsReport(UUID sessio
}
}

public DownloadableReportResponse generatePenMergesReport() {
DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
LocalDateTime fromDate = LocalDate.now().minusMonths(13).atStartOfDay();
LocalDateTime toDate = LocalDate.now().atStartOfDay();
List<StudentMergeResult> results = studentMergeService.getMergedStudentsForDateRange(fromDate.format(formatter), toDate.format(formatter));
List<String> headers = Arrays.stream(PenMergesHeader.values()).map(PenMergesHeader::getCode).toList();
CSVFormat csvFormat = CSVFormat.DEFAULT.builder()
.build();
try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(byteArrayOutputStream));
CSVPrinter csvPrinter = new CSVPrinter(writer, csvFormat);

csvPrinter.printRecord(Arrays.asList("Student Assessment Merged PENS Date: " + LocalDate.now()));
csvPrinter.printRecord(Arrays.asList("--------------------------------------------------------------------------------"));
csvPrinter.printRecord(headers);

for (StudentMergeResult result : results) {
if(StringUtils.isNotEmpty(result.getCurrentPEN()) && StringUtils.isNotEmpty(result.getMergedPEN())) {
csvPrinter.printRecord(result.getCurrentPEN(),result.getMergedPEN());
}
}
csvPrinter.flush();

var downloadableReport = new DownloadableReportResponse();
downloadableReport.setReportType(EASReportTypeCode.PEN_MERGES.getCode());
downloadableReport.setDocumentData(Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray()));

return downloadableReport;
} catch (IOException e) {
throw new EasAPIRuntimeException(e);
}
}

private List<String> prepareEnrolmentFteDataForCsv(AssessmentStudentEntity student, SchoolTombstone school, Optional<SchoolTombstone> assessmentCenter) {
return new ArrayList<>(Arrays.asList(
school.getMincode(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,56 @@
package ca.bc.gov.educ.eas.api.service.v1;

import ca.bc.gov.educ.eas.api.mappers.v1.StudentMergeMapper;
import ca.bc.gov.educ.eas.api.rest.RestUtils;
import ca.bc.gov.educ.eas.api.struct.external.studentapi.v1.Student;
import ca.bc.gov.educ.eas.api.struct.v1.StudentMerge;
import ca.bc.gov.educ.eas.api.struct.v1.StudentMergeResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.UUID;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
@Slf4j
public class StudentMergeService {

private static final StudentMergeMapper mapper = StudentMergeMapper.mapper;
private final RestUtils restUtils;

@Autowired
public StudentMergeService(RestUtils restUtils){
public StudentMergeService(RestUtils restUtils) {
this.restUtils = restUtils;
}

public List<StudentMerge> getMergedStudentsForDateRange(String createDateStart, String createDateEnd){
public List<StudentMergeResult> getMergedStudentsForDateRange(String createDateStart, String createDateEnd) {
UUID correlationID = UUID.randomUUID();
List<StudentMergeResult> mergeStudentResults = new ArrayList<>();
log.info("Fetching student merge records created between {} and {} with correlation ID: {}", createDateStart, createDateEnd, correlationID);
return restUtils.getMergedStudentsForDateRange(correlationID, createDateStart, createDateEnd);
List<StudentMerge> results = restUtils.getMergedStudentsForDateRange(correlationID, createDateStart, createDateEnd);
if (!CollectionUtils.isEmpty(results)) {
Set<String> studentIDs = results.stream()
.flatMap(studentMerge -> Stream.of(studentMerge.getStudentID(), studentMerge.getMergeStudentID()))
.collect(Collectors.toSet());
List<Student> students = Optional.ofNullable(restUtils.getStudents(correlationID, studentIDs)).orElseGet(Collections::emptyList);
results.stream()
.forEach(studentMerge -> {
StudentMergeResult studentMergeResult = mapper.toStructure(studentMerge);
Optional<Student> mergedPEN = students.stream()
.filter(student -> student.getStudentID().equals(studentMerge.getStudentID()))
.findFirst();
Optional<Student> currentPEN = students.stream()
.filter(student -> student.getStudentID().equals(studentMerge.getMergeStudentID()))
.findFirst();

currentPEN.ifPresent(pen -> studentMergeResult.setCurrentPEN(pen.getPen()));
mergedPEN.ifPresent(pen -> studentMergeResult.setMergedPEN(pen.getPen()));
mergeStudentResults.add(studentMergeResult);
});
}
return mergeStudentResults;
}
}
Loading

0 comments on commit d62fc19

Please sign in to comment.