diff --git a/pom.xml b/pom.xml index 90f6dc1154fc1cab336b984d952b2de1b59e398e..b512d7a516fb3f7c5ee858ce688d4c665732c384 100644 --- a/pom.xml +++ b/pom.xml @@ -21,6 +21,10 @@ <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-mail</artifactId> + </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/ExamsAndAdmissionsApplication.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/ExamsAndAdmissionsApplication.java index b4e6efc05445ff0a9b5cc14d021f88123b1b8170..b41d139041c331aac754499eb513d9a9967e89a5 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/ExamsAndAdmissionsApplication.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/ExamsAndAdmissionsApplication.java @@ -51,8 +51,10 @@ public class ExamsAndAdmissionsApplication { public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") - .allowedOriginPatterns("http://localhost:*") - .allowedHeaders("*"); + .allowedOriginPatterns("*") + .maxAge(3600) + .allowedHeaders("*") + .exposedHeaders("Authorization"); } @Autowired @@ -70,7 +72,7 @@ public class ExamsAndAdmissionsApplication { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); - config.addAllowedOriginPattern("http://localhost:*"); + config.addAllowedOriginPattern("*"); config.addAllowedHeader("*"); config.addAllowedMethod("*"); source.registerCorsConfiguration("/**", config); diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/controller/ExamCycleController.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/controller/ExamCycleController.java index 4aac083f0dc593b84f1fda563588c9817e102740..4d320600388964aa692a5157c3eecd21f3d9cb21 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/controller/ExamCycleController.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/controller/ExamCycleController.java @@ -6,7 +6,6 @@ import com.tarento.upsmf.examsAndAdmissions.model.ResponseDto; import com.tarento.upsmf.examsAndAdmissions.model.dto.ExamCycleWithExamsDTO; import com.tarento.upsmf.examsAndAdmissions.model.dto.SearchExamCycleDTO; import com.tarento.upsmf.examsAndAdmissions.repository.CourseRepository; -import com.tarento.upsmf.examsAndAdmissions.repository.ExamEntityRepository; import com.tarento.upsmf.examsAndAdmissions.service.ExamCycleService; import com.tarento.upsmf.examsAndAdmissions.util.Constants; import org.springframework.beans.factory.annotation.Autowired; @@ -106,5 +105,15 @@ public class ExamCycleController { return new ResponseEntity<>(response, response.getResponseCode()); } + @GetMapping("/examCyclesByCouses") + public ResponseEntity<ResponseDto> getExamCycleDetailsByInstitute(@RequestParam Long instituteId){ + try { + List<ExamCycle> examDetails = service.getExamCyclesByExamCycleAndCourse(instituteId); + return FeeController.handleSuccessResponse(examDetails); + }catch (Exception e){ + return FeeController.handleErrorResponse(e); + } + } + } \ No newline at end of file diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/controller/FeeController.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/controller/FeeController.java index d3af51f4e700b0508abb502ee555484378685f79..6b51baa6ae0e00fc73cf0cf9a6d4c6301f256c94 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/controller/FeeController.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/controller/FeeController.java @@ -52,10 +52,11 @@ public class FeeController { } } - @GetMapping("/{refNo}/details") - public ResponseEntity<ResponseDto> getStudentDetailsByRefNo(@PathVariable("refNo") String refNo) { + @GetMapping("/{examCycleId}/{instituteId}/details") + public ResponseEntity<ResponseDto> getStudentDetailsByRefNo(@PathVariable("examCycleId") Long examCycleId, + @PathVariable("instituteId") Long instituteId) { try { - List<StudentExamFeeDto> studentExam = feeService.getStudentDetailsByRefNo(refNo); + List<StudentExamFeeDto> studentExam = feeService.getStudentDetailsByExamCycleIdAndInstituteId(examCycleId, instituteId); return handleSuccessResponse(studentExam); } catch (Exception e) { return handleErrorResponse(e); @@ -71,7 +72,6 @@ public class FeeController { return handleErrorResponse(e); } } - public static ResponseEntity<ResponseDto> handleSuccessResponse(Object response) { ResponseParams params = new ResponseParams(); params.setStatus(HttpStatus.OK.getReasonPhrase()); diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/controller/HallTicketController.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/controller/HallTicketController.java index df63e77424a88709e659e615f18cf562f8ad6cf8..dad3d39b18eacb8bf07b1853274e46ac8e41c7c4 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/controller/HallTicketController.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/controller/HallTicketController.java @@ -59,6 +59,19 @@ public class HallTicketController { return ResponseEntity.status(response.getResponseCode()).body(response); } + @GetMapping("/examCycle") + public ResponseEntity<ResponseDto> downloadStudentHallTicketByStudentId(@RequestParam Long id, @RequestParam Long examCycleId) { + ResponseDto response; + try { + response = hallTicketService.getHallTicketBlobResourcePathByStudentId(id, examCycleId); + } catch (Exception e) { + log.error("Error fetching hall ticket for student ID: {}", id, e); + response = new ResponseDto(Constants.API_HALLTICKET_GET); + ResponseDto.setErrorResponse(response, "GENERAL_ERROR", e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + } + return ResponseEntity.status(response.getResponseCode()).body(response); + } + private Resource extractResourceFromResponseDto(ResponseDto responseDto) { String base64EncodedData = (String) responseDto.get(Constants.RESPONSE); diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/controller/InstituteController.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/controller/InstituteController.java index 4d7784a078a188aab846d7eee809bc1829e773b8..a4bdd12b60efc0f9eb8f777d5086cdae8b0936ba 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/controller/InstituteController.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/controller/InstituteController.java @@ -1,6 +1,5 @@ package com.tarento.upsmf.examsAndAdmissions.controller; -import com.tarento.upsmf.examsAndAdmissions.model.DispatchTracker; import com.tarento.upsmf.examsAndAdmissions.model.Institute; import com.tarento.upsmf.examsAndAdmissions.model.ResponseDto; import com.tarento.upsmf.examsAndAdmissions.model.dto.ApprovalRejectionDTO; @@ -12,17 +11,11 @@ import com.tarento.upsmf.examsAndAdmissions.service.InstituteService; import com.tarento.upsmf.examsAndAdmissions.util.Constants; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; - import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; -import java.time.LocalDate; - -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; import java.util.List; import java.util.stream.Collectors; diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/controller/StudentController.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/controller/StudentController.java index ec0365f9a65825609adc1bf49c4b12ac8beb70ea..f4beecd428a82a3ddb68bb43ee815c77e1066065 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/controller/StudentController.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/controller/StudentController.java @@ -80,7 +80,7 @@ public class StudentController { return ResponseEntity.status(response.getResponseCode()).body(response); } - @GetMapping("/{keycloakId}") + @GetMapping("/keycloak/{keycloakId}") public ResponseEntity<ResponseDto> getStudentByKeycloak(@PathVariable String keycloakId) { ResponseDto response = studentService.getStudentByKeycloakId(keycloakId); return ResponseEntity.status(response.getResponseCode()).body(response); diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/controller/StudentResultController.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/controller/StudentResultController.java index 6756ff51cc1bba49f7c57b8af5f012b9de8a1429..e2725bebe960aa7cfdb6600b4aca79f5f6661e0c 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/controller/StudentResultController.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/controller/StudentResultController.java @@ -48,8 +48,8 @@ public class StudentResultController { } @GetMapping("/results") - public ResponseEntity<ResponseDto> viewResults(@RequestParam String enrolmentNumber, @RequestParam String dateOfBirth, @RequestParam Long examCycleId) { - return new ResponseEntity<>(studentResultService.findByEnrollmentNumberAndDateOfBirth(enrolmentNumber, LocalDate.parse(dateOfBirth), examCycleId), HttpStatus.OK); + public ResponseEntity<ResponseDto> viewResults(@RequestParam String enrolmentNumber, @RequestParam Long examCycleId) { + return new ResponseEntity<>(studentResultService.findByEnrollmentNumberAndDateOfBirth(enrolmentNumber, examCycleId), HttpStatus.OK); } @PostMapping("/requestRetotalling") diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/Exam.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/Exam.java index fd6e5b66ab85d1af5e11934359e90ce11bf9746b..088ff15c0af3222afaf1c8560411012a26e1ac27 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/Exam.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/Exam.java @@ -67,4 +67,7 @@ public class Exam implements Serializable { private Integer maximumMark; @Column(name ="lastDate_To_UploadMarks" ) private LocalDate lastDateToUploadMarks; + + @Column(name ="amount") + private Double amount; } diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/StudentExam.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/StudentExam.java index 91ced179979bf8c51caa0a1ab2ac6718a5806512..539fd5d7b8a6828fb1487b4ff8be0a7fb761a01b 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/StudentExam.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/StudentExam.java @@ -36,6 +36,10 @@ public class StudentExam implements Serializable { @Column(name = "status", nullable = false, columnDefinition = "varchar(50) default 'INITIATED'") private Status status; + @OneToOne + @JoinColumn(name = "exam_cycle_id") + private ExamCycle examCycle; + public enum Status { INITIATED, PAID, FAILED, REFUND, ABANDONED } diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/ExamFeeDto.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/ExamFeeDto.java index c008115761ee29c1854dbc22c5682925b2b8a52d..349ab342ea431fde3813f94f65bb0ab7cca86bd1 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/ExamFeeDto.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/ExamFeeDto.java @@ -6,7 +6,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; -import java.util.Map; +import java.util.List; @Data @NoArgsConstructor @@ -18,7 +18,7 @@ public class ExamFeeDto implements Serializable { private Long instituteId; - private Map<String, Map<Long,Double>> studentExam; + private List<StudentExamDto> studentExam; private Double amount; diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/ExamFeeRequestDto.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/ExamFeeRequestDto.java new file mode 100644 index 0000000000000000000000000000000000000000..23a990b40fbc86af0163c07a958995fcc6f81b73 --- /dev/null +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/ExamFeeRequestDto.java @@ -0,0 +1,14 @@ +package com.tarento.upsmf.examsAndAdmissions.model.dto; + +import lombok.*; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@ToString +@Builder +public class ExamFeeRequestDto { + + private Long id; + private Double fee; +} diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/ExamFeeSearchDto.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/ExamFeeSearchDto.java index 20d59f49cac198ed1bd5d55000641d812bfcaaed..1071e98d8573cd38b245517c73ed2d19f147eec1 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/ExamFeeSearchDto.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/ExamFeeSearchDto.java @@ -15,4 +15,5 @@ public class ExamFeeSearchDto { private int page; private int size; private Map<String, String> sort; + private Map<String, String> filter; } diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/ExamInfoDto.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/ExamInfoDto.java index 29accd39dbbf7482b2a5c334034beeb0dbe05a0b..595a13d46885bf4c36a51cbb0f1a1d24fd9be115 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/ExamInfoDto.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/ExamInfoDto.java @@ -12,4 +12,6 @@ import lombok.Setter; public class ExamInfoDto { private Long id; private String name; + private boolean isFeesPaid; + private double amount; } diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/ExamSearchResponseDto.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/ExamSearchResponseDto.java index 0620782384c34fac736048b214668dbd76542fe5..db020923f438bb19c7ba1ba1e5de30fed9769d79 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/ExamSearchResponseDto.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/ExamSearchResponseDto.java @@ -15,5 +15,5 @@ import java.util.List; public class ExamSearchResponseDto implements Serializable { private long count; - private List<ExamFee> examFees; + private List<InstituteExamFeeResponse> examFees; } diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/InstituteExamFeeResponse.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/InstituteExamFeeResponse.java new file mode 100644 index 0000000000000000000000000000000000000000..e0a8d249d8745ff7828faf447b00715232dd0cb6 --- /dev/null +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/InstituteExamFeeResponse.java @@ -0,0 +1,23 @@ +package com.tarento.upsmf.examsAndAdmissions.model.dto; + +import com.tarento.upsmf.examsAndAdmissions.model.ExamCycle; +import com.tarento.upsmf.examsAndAdmissions.model.Institute; +import lombok.*; + +import javax.persistence.Transient; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@ToString +@Builder +public class InstituteExamFeeResponse { + + private ExamCycle examCycle; + private Institute institute; + private long totalStudentsCount; + private long totalPaidCount; + private double totalPaidAmount; + + +} diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/StudentExamDto.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/StudentExamDto.java new file mode 100644 index 0000000000000000000000000000000000000000..344f2ba841beb8171803fe731d1019ae00667128 --- /dev/null +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/StudentExamDto.java @@ -0,0 +1,17 @@ +package com.tarento.upsmf.examsAndAdmissions.model.dto; + +import lombok.*; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@ToString +@Builder +public class StudentExamDto { + + private Long studentId; + private List<ExamFeeRequestDto> exam; + +} diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/ValidationResultDto.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/ValidationResultDto.java new file mode 100644 index 0000000000000000000000000000000000000000..3545d4aa65c9ea48dadb20f1b23d4bfbf324edf9 --- /dev/null +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/model/dto/ValidationResultDto.java @@ -0,0 +1,30 @@ +package com.tarento.upsmf.examsAndAdmissions.model.dto; + +import com.tarento.upsmf.examsAndAdmissions.model.StudentResult; +import lombok.*; + +import java.util.List; + +public class ValidationResultDto { + private boolean isValid; + @Getter + private List<String> validationErrors; + @Getter + private List<StudentResult> savedEntities; + + public boolean isValid() { + return isValid; + } + + public void setValid(boolean isValid) { + this.isValid = isValid; + } + + public void setValidationErrors(List<String> validationErrors) { + this.validationErrors = validationErrors; + } + + public void setSavedEntities(List<StudentResult> savedEntities) { + this.savedEntities = savedEntities; + } +} diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/AttendanceRepository.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/AttendanceRepository.java index 09a8da8a311be358f299e3bac3034aaff15b6158..113e6d8d3a18c788c99b4fce0e351b043ff45f1e 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/AttendanceRepository.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/AttendanceRepository.java @@ -11,4 +11,6 @@ public interface AttendanceRepository extends JpaRepository<AttendanceRecord, Lo boolean existsByStudentEnrollmentNumber(String studentEnrollmentNumber); AttendanceRecord findByStudentEnrollmentNumber(String studentEnrollmentNumber); List<AttendanceRecord> findByExamCycleId(Long examCycleId); + + List<AttendanceRecord> findByExamCycleData(String examCycleName); } \ No newline at end of file diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/CourseRepository.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/CourseRepository.java index 67206cf66d3274e755ff458fbb8e6e40bad3dbf1..b60bb1e1b6d696df6373632a25d6973b5df30be2 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/CourseRepository.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/CourseRepository.java @@ -5,6 +5,7 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import java.util.List; import java.util.Optional; public interface CourseRepository extends JpaRepository<Course, Long> { @@ -14,4 +15,6 @@ public interface CourseRepository extends JpaRepository<Course, Long> { Optional<Course> findByCourseNameIgnoreCase(@Param("courseName") String courseName); Course findByInstituteId(Long id); + + List<Course> findAllByInstituteId(Long instituteId); } diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/ExamCycleRepository.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/ExamCycleRepository.java index 8db365c814ad4fc63ae79c2ea39f7293934d1ea1..d41263de9ce8ff9ad027fe7e3ab95e5d3560e92f 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/ExamCycleRepository.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/ExamCycleRepository.java @@ -15,6 +15,9 @@ public interface ExamCycleRepository extends JpaRepository<ExamCycle, Long> { // Fetch all non-obsolete records List<ExamCycle> findByObsolete(Integer value); + @Query("SELECT ec.examCycleName FROM ExamCycle ec WHERE ec.id = :examCycleId") + String getExamCycleNameById(@Param("examCycleId") Long examCycleId); + // Fetch a non-obsolete record by ID Optional<ExamCycle> findByIdAndObsolete(Long id, Integer value); ExamCycle findByExamCycleName(String name); @@ -26,4 +29,6 @@ public interface ExamCycleRepository extends JpaRepository<ExamCycle, Long> { @Query(value = "select * from exam_cycle ec where ec.course_id =:courseId and date_part('year', ec.start_date) = :startYear and date_part('year', ec.end_date) <= :endYear", nativeQuery = true) List<ExamCycle> searchExamCycleByCourseIdAndStartYearAndEndYear(@Param("courseId") String courseId, @Param("startYear") Integer startYear, @Param("endYear") Integer endYear); + + List<ExamCycle> findByCourseInAndEndDateAfter(List<Course> courses, LocalDate currentDate); } diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/ExamFeeRepository.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/ExamFeeRepository.java index 08bf1bb38601ba41be7b1475eff72e7c00edb94d..0c353f6a27c7de6f502e741eecf215cb04211289 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/ExamFeeRepository.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/ExamFeeRepository.java @@ -1,13 +1,21 @@ package com.tarento.upsmf.examsAndAdmissions.repository; import com.tarento.upsmf.examsAndAdmissions.model.ExamFee; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface ExamFeeRepository extends PagingAndSortingRepository<ExamFee, Long> { ExamFee findByReferenceNo(String referenceNo); Boolean existsByReferenceNo(String referenceNo); + + Page<ExamFee> findAllByExamCycleId(Long examCycleId, PageRequest pageRequest); + + List<ExamFee> findAllByInstituteIdAndExamCycleId(Long instituteId, Long examCycleId); } diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/ExamRepository.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/ExamRepository.java index f914cb86c6747effd16b853f622a7e0f1a386a6a..62b100310fa073d6cd5db5737a1b7446b7e6d28c 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/ExamRepository.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/ExamRepository.java @@ -26,4 +26,5 @@ public interface ExamRepository extends JpaRepository<Exam, Long> { @Query("SELECT e FROM Exam e JOIN StudentExamRegistration ser ON e.id = ser.exam.id WHERE ser.student.id = :studentId AND e.examCycleId = :examCycleId") List<Exam> findRegisteredExamsForStudentInCycle(Long studentId, Long examCycleId); + String getExamNameById(Long exam); } diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/StudentExamFeeRepository.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/StudentExamFeeRepository.java index e788dcea30f0a6da6a0a21b966f1d92a20daf5b6..2c598ba8658fc6e158d441375ddc4220b3a11aeb 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/StudentExamFeeRepository.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/StudentExamFeeRepository.java @@ -20,4 +20,10 @@ public interface StudentExamFeeRepository extends PagingAndSortingRepository<Stu List<Long> getStudentIdsByRefNo(String refNo); List<StudentExam> findByReferenceNo(String referenceNo); + + List<StudentExam> findAllByReferenceNoAndExamCycleId(String referenceNo, Long examCycleId); + + @Query(value = "select * from student_exam_mapping where reference_no in (:refNos) and exam_cycle_id=:examCycleId and status =:status", nativeQuery = true) + List<StudentExam> findAllByExamCycleIdAndStatusAndReferenceNoIn(Long examCycleId, List<String> refNos, String status); + } diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/StudentExamRegistrationRepository.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/StudentExamRegistrationRepository.java index 319f0524555d1acd7e46de02b2c57ac62f80bf78..be2e6ec4bf7423f33e18b55405605aac83b35bc5 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/StudentExamRegistrationRepository.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/StudentExamRegistrationRepository.java @@ -24,6 +24,9 @@ public interface StudentExamRegistrationRepository extends JpaRepository<Student Optional<StudentExamRegistration> findByIdAndStudent_DateOfBirth(Long id, LocalDate localDate); + @Query(value = "SELECT * from student_exam_registration where student_id=:id and exam_cycle_id=:examCycleId", nativeQuery = true) + List<StudentExamRegistration> findAllByStudent_IdAndExam_Id(Long id, Long examCycleId); + List<StudentExamRegistration> findByExamCenter(ExamCenter originalExamCenter); List<StudentExamRegistration> findByInstituteIdAndExamCenterIsNull(Long instituteId); @@ -35,8 +38,13 @@ public interface StudentExamRegistrationRepository extends JpaRepository<Student @Modifying - @Query(value = "update student_exam_registration set is_fees_paid =:status where student_id =:studentId", nativeQuery = true) - void updateExamFeeByStudentId(@Param("status") Boolean status, @Param("studentId") Long studentId); + @Query(value = "update student_exam_registration set remarks=:remarks, status=:status, is_fees_paid =:is_fees_paid " + + "where student_id =:studentId and institute_id=:institute_id " + + "and exam_cycle_id=:exam_cycle_id and exam_id=:exam_id", nativeQuery = true) + void updateExamFeeByStudentId(@Param("is_fees_paid") Boolean isFeesPaid, @Param("status") String status, + @Param("remarks") String remarks, @Param("studentId") Long studentId, + @Param("institute_id") Long instituteId, @Param("exam_cycle_id") Long examCycleId, + @Param("exam_id") Long examId); List<StudentExamRegistration> findByExamCenterIsNullAndInstitute(Institute institute); diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/StudentResultRepository.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/StudentResultRepository.java index 69aa6eeee6252a44b6bd5ac14511fd044c3a8497..f1823a95bb2b0a286173af2c4abc4c7075b96c11 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/StudentResultRepository.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/repository/StudentResultRepository.java @@ -2,6 +2,7 @@ package com.tarento.upsmf.examsAndAdmissions.repository; import com.tarento.upsmf.examsAndAdmissions.model.Exam; import com.tarento.upsmf.examsAndAdmissions.model.ExamCycle; +import com.tarento.upsmf.examsAndAdmissions.model.StudentExamRegistration; import com.tarento.upsmf.examsAndAdmissions.model.StudentResult; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; @@ -20,9 +21,9 @@ public interface StudentResultRepository extends JpaRepository<StudentResult, Lo List<StudentResult> findByCourse_IdAndExam_ExamCycleIdAndPublished(Long courseId, Long examCycleId, boolean b); - List<StudentResult> findByStudent_EnrollmentNumberAndStudent_DateOfBirthAndExamCycle_IdAndPublished(String enrollmentNumber, LocalDate dateOfBirth, Long examCycleId, boolean published); +// List<StudentResult> findByStudent_EnrollmentNumberAndStudent_DateOfBirthAndExamCycle_IdAndPublished(String enrollmentNumber, LocalDate dateOfBirth, Long examCycleId, boolean published); - boolean existsByEnrollmentNumber(String enrollmentNumber); + boolean existsByEnrollmentNumberAndFirstNameAndLastName(String enrollmentNumber,String firstName, String lastName); List<StudentResult> findByExamCycleAndExam(Long examCycle, Exam exam); @@ -50,6 +51,17 @@ public interface StudentResultRepository extends JpaRepository<StudentResult, Lo Optional<StudentResult> findByExamId(Long id); - List<StudentResult> findByExamIdAndInstituteId(Long id, Long instituteId); + @Query("SELECT sr FROM StudentResult sr WHERE sr.exam_name = :examName AND sr.instituteId = :instituteId") + List<StudentResult> findByExamNameAndInstituteId(@Param("examName") String examName, @Param("instituteId") Long instituteId); + + List<StudentResult> findByExamExamNameAndInstituteId(String examName, Long instituteId); + + List<StudentResult> findByStudent_EnrollmentNumberAndExamCycle_IdAndPublished(String enrollmentNumber, Long examCycleId, boolean b); + + @Query("SELECT sr FROM StudentResult sr WHERE sr.examCycle_name = :examCycleName AND sr.exam_name = :examName AND sr.student.institute.id = :institute") + List<StudentResult> findByExamCycleNameAndExamNameAndInstitute(String examCycleName, String examName, Long institute); + + @Query("SELECT sr FROM StudentResult sr WHERE sr.examCycle_name = :examCycleName") + List<StudentResult> findByExamCycleName(String examCycleName); } diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/AttendanceService.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/AttendanceService.java index fa1db3b1854387cd709fc3fae8c45b745d7d4b8f..fbd4ac25898b161ab365b35f785c46f3b61465b0 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/AttendanceService.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/AttendanceService.java @@ -251,16 +251,17 @@ public class AttendanceService { } List<AttendanceRecord> dtoList = dataImporterService.convertJsonToDtoList(jsonArray, AttendanceRecord.class); - UploadStatusDetails statusDetails = dataImporterService.saveDtoListToPostgres(dtoList, attendanceRepository); + List<AttendanceRecord> savedEntities = dataImporterService.saveDtoListToPostgres(dtoList, attendanceRepository); - if (statusDetails.isSuccess()) { - String message = String.format("Bulk attendance upload: %d total, %d uploaded, %d skipped.", - statusDetails.getTotalRecords(), statusDetails.getUploadedRecords(), statusDetails.getSkippedRecords()); + if (!savedEntities.isEmpty()) { + String message = String.format("Bulk attendance upload: %d records saved.", savedEntities.size()); response.put(Constants.MESSAGE, message); + response.put("savedRecords", savedEntities); // Add the saved records to the response response.setResponseCode(HttpStatus.OK); } else { - return ResponseDto.setErrorResponse(response, "FILE_PROCESSING_FAILED", statusDetails.getErrorMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + return ResponseDto.setErrorResponse(response, "FILE_PROCESSING_FAILED", "No records were saved.", HttpStatus.INTERNAL_SERVER_ERROR); } + } catch (Exception e) { return ResponseDto.setErrorResponse(response, "INTERNAL_ERROR", "An unexpected error occurred: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); } @@ -269,8 +270,8 @@ public class AttendanceService { } public ResponseDto getByExamCycleId(Long ExamCycleId) { ResponseDto response = new ResponseDto(Constants.API_ATTENDANCE_BY_EXAM_CYCLE_ID); - List<AttendanceRecord> records = attendanceRepository.findByExamCycleId(ExamCycleId); - + String examCycleName = examCycleRepository.getExamCycleNameById(ExamCycleId); + List<AttendanceRecord> records = attendanceRepository.findByExamCycleData(examCycleName); if (records.isEmpty()) { ResponseDto.setErrorResponse(response, "NO_RECORDS_FOUND", "No attendance records found", HttpStatus.NOT_FOUND); } else { diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/DataImporterService.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/DataImporterService.java index b9f1799ca47411fda2c37254f18ddfd98aff0a1b..67d760afb089e5f5dde03b0eade56c4edcaaa968 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/DataImporterService.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/DataImporterService.java @@ -10,6 +10,7 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.tarento.upsmf.examsAndAdmissions.enums.ApprovalStatus; import com.tarento.upsmf.examsAndAdmissions.exception.ValidationException; import com.tarento.upsmf.examsAndAdmissions.model.*; +import com.tarento.upsmf.examsAndAdmissions.model.dto.ValidationResultDto; import com.tarento.upsmf.examsAndAdmissions.repository.*; import com.tarento.upsmf.examsAndAdmissions.util.DataValidation; import org.apache.commons.csv.CSVFormat; @@ -55,6 +56,14 @@ public class DataImporterService { private ExamEntityRepository examCycleRepository; @Autowired private InstituteRepository instituteRepository; + @Autowired + private CourseRepository courseRepository; + @Autowired + private ExamCycleRepository cycleRepository; + @Autowired + private ExamRepository examRepository; + @Autowired + private StudentRepository studentRepository; public JSONArray excelToJson(MultipartFile excelFile) throws IOException, JSONException { try (InputStream inputStream = excelFile.getInputStream(); @@ -68,91 +77,100 @@ public class DataImporterService { JSONArray jsonArray = StreamSupport.stream(sheet.spliterator(), false) .skip(1) // Skip the header row .map(row -> { - JSONObject jsonObject = new JSONObject(); - IntStream.range(0, columnNames.size()) - .forEach(columnIndex -> { - Cell currentCell = row.getCell(columnIndex); - String columnName = columnNames.get(columnIndex); - - try { - if (currentCell != null) { // Add this null check - switch (currentCell.getCellType()) { - case STRING: - jsonObject.put(columnName, currentCell.getStringCellValue()); - break; - case NUMERIC: - if (DateUtil.isCellDateFormatted(currentCell)) { - jsonObject.put(columnName, currentCell.getDateCellValue()); - } else { - jsonObject.put(columnName, currentCell.getNumericCellValue()); - } - break; - case BOOLEAN: - jsonObject.put(columnName, currentCell.getBooleanCellValue()); - break; - case BLANK: - jsonObject.put(columnName, ""); - break; - default: - jsonObject.put(columnName, ""); + if (StreamSupport.stream(row.spliterator(), false).noneMatch(Objects::isNull)) { + // Process the row + JSONObject jsonObject = new JSONObject(); + IntStream.range(0, columnNames.size()) + .forEach(columnIndex -> { + Cell currentCell = row.getCell(columnIndex); + String columnName = columnNames.get(columnIndex); + + try { + if (currentCell != null) { // Add this null check + switch (currentCell.getCellType()) { + case STRING: + jsonObject.put(columnName, currentCell.getStringCellValue()); + break; + case NUMERIC: + if (DateUtil.isCellDateFormatted(currentCell)) { + jsonObject.put(columnName, currentCell.getDateCellValue()); + } else { + jsonObject.put(columnName, currentCell.getNumericCellValue()); + } + break; + case BOOLEAN: + jsonObject.put(columnName, currentCell.getBooleanCellValue()); + break; + case BLANK: + jsonObject.put(columnName, ""); + break; + default: + jsonObject.put(columnName, ""); + } + } else { + jsonObject.put(columnName, ""); // Handle null cells } - } else { - jsonObject.put(columnName, ""); // Handle null cells + } catch (JSONException e) { + System.out.println("JsonError"); + // Handle JSONException if needed } - } catch (JSONException e) { - System.out.println("JsonError"); - // Handle JSONException if needed - } - }); - return jsonObject; + }); + return jsonObject; + } + return null; }) + .filter(Objects::nonNull) // Filter out rows with null values .collect(Collectors.collectingAndThen(Collectors.toList(), JSONArray::new)); return jsonArray; } } + public JSONArray csvToJson(MultipartFile csvFile, Map<String, Class<?>> columnConfig) throws IOException { try (Reader reader = new InputStreamReader(csvFile.getInputStream()); CSVParser csvParser = CSVFormat.DEFAULT.withHeader().parse(reader)) { List<Map<String, Object>> records = csvParser.getRecords().stream() .map(record -> { - Map<String, Object> map = new HashMap<>(); - for (Map.Entry<String, String> entry : record.toMap().entrySet()) { - String columnName = entry.getKey(); - String columnValue = entry.getValue(); - Class<?> columnType = columnConfig.get(columnName); - - if (columnType == Date.class) { - SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy"); - SimpleDateFormat timeFormat = new SimpleDateFormat("h:mm a"); - - try { - if (columnValue != null && !columnValue.isEmpty()) { - if (columnName.equals("Start Time") || columnName.equals("End Time")) { - Date time = timeFormat.parse(columnValue); - map.put(columnName, timeFormat.format(time)); // Format the time as a string - } else if (columnName.equals("Start Date") || columnName.equals("End Date")) { - Date date = dateFormat.parse(columnValue); - map.put(columnName, dateFormat.format(date)); // Format the date as a string - } else { - // Handle other date or time columns if needed + if (record.toMap().values().stream().noneMatch(Objects::isNull)) { + // Process the row + Map<String, Object> map = new HashMap<>(); + for (Map.Entry<String, String> entry : record.toMap().entrySet()) { + String columnName = entry.getKey(); + String columnValue = entry.getValue(); + Class<?> columnType = columnConfig.get(columnName); + + if (columnValue != null && !columnValue.isEmpty()) { + if (columnType == Date.class) { + SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy"); + SimpleDateFormat timeFormat = new SimpleDateFormat("h:mm a"); + + try { + if (columnName.equals("Start Time") || columnName.equals("End Time")) { + Date time = timeFormat.parse(columnValue); + map.put(columnName, timeFormat.format(time)); // Format the time as a string + } else if (columnName.equals("Start Date") || columnName.equals("End Date")) { + Date date = dateFormat.parse(columnValue); + map.put(columnName, dateFormat.format(date)); // Format the date as a string + } + } catch (ParseException e) { + e.printStackTrace(); // Handle parsing exceptions + map.put(columnName, null); } } else { - // Handle cases where the columnValue is empty or null - map.put(columnName, null); + // Handle other columns as strings or based on their data types + map.put(columnName, columnValue); } - } catch (ParseException e) { - e.printStackTrace(); // Handle parsing exceptions + } else { + // Handle cases where the columnValue is empty or null map.put(columnName, null); } - } else { - // Handle other columns as strings or based on their data types - map.put(columnName, columnValue); } + return map; } - return map; + return null; }) + .filter(Objects::nonNull) // Filter out rows with null values .collect(Collectors.toList()); try { @@ -163,7 +181,6 @@ public class DataImporterService { } } - public JSONArray filterColumns(JSONArray jsonArray, String... selectedColumns) throws JSONException { JSONArray filteredArray = new JSONArray(); @@ -261,37 +278,22 @@ public class DataImporterService { } } - public UploadStatusDetails saveDtoListToPostgres(List<AttendanceRecord> dtoList, AttendanceRepository repository) { - int total = dtoList.size(); - int uploaded = 0; - int skipped = 0; - - List<AttendanceRecord> entityList = new ArrayList<>(); - + public List<AttendanceRecord> saveDtoListToPostgres(List<AttendanceRecord> dtoList, AttendanceRepository repository) { + List<AttendanceRecord> savedEntities = new ArrayList<>(); for (AttendanceRecord dto : dtoList) { if (isDtoEffectivelyEmpty(dto)) { - skipped++; continue; } - if (!checkIfDataExists(dto)) { AttendanceRecord entity = getAttendanceRecord(dto); - - entityList.add(entity); - uploaded++; - } else { - skipped++; + AttendanceRecord savedEntity = repository.save(entity); + savedEntities.add(savedEntity); } } - - try { - repository.saveAll(entityList); - return new UploadStatusDetails(total, uploaded, skipped, true, null); - } catch (Exception e) { - return new UploadStatusDetails(total, uploaded, skipped, false, e.getMessage()); - } + return savedEntities; } + private static AttendanceRecord getAttendanceRecord(AttendanceRecord dto) { AttendanceRecord entity = new AttendanceRecord(); @@ -311,157 +313,148 @@ public class DataImporterService { return entity; } - public boolean convertResultDtoListToEntities(List<StudentResult> dtoList, StudentResultRepository repository, Long instituteId) throws ValidationException { + public ValidationResultDto convertResultDtoListToEntities(List<StudentResult> dtoList, StudentResultRepository repository, Long instituteId) { List<StudentResult> entityList = new ArrayList<>(); boolean isValid = true; - List<String> validationErrors = new ArrayList<>(); + List<String> validationErrors = new ArrayList(); for (StudentResult dto : dtoList) { boolean isDuplicate = checkIfDataExists(dto); if (!isDuplicate) { if (!DataValidation.isFirstNameValid(dto.getFirstName())) { - validationErrors.add("- First Name is invalid: " + dto.getFirstName()); + validationErrors.add("- First Name is invalid: " + dto.getFirstName() + " First name has to contain alphabetic values only"); } if (!DataValidation.isLastNameValid(dto.getLastName())) { - validationErrors.add("- Last Name is invalid: " + dto.getLastName()); + validationErrors.add("- Last Name is invalid: " + dto.getLastName()+ " First name has to contain alphabetic values only"); } if (!DataValidation.isEnrollmentNumberValid(dto.getEnrollmentNumber())) { - validationErrors.add("- Enrollment Number is invalid: " + dto.getEnrollmentNumber()); + validationErrors.add("- Enrollment Number is invalid: " + dto.getEnrollmentNumber()+" Enrollment number has to contain numerical values prefixed with EN"); } if (!DataValidation.isMotherNameValid(dto.getMotherName())) { - validationErrors.add("- Mother's Name is invalid: " + dto.getMotherName()); + validationErrors.add("- Mother's Name is invalid: " + dto.getMotherName()+ " First name has to contain alphabetic values only"); } if (!DataValidation.isFatherNameValid(dto.getFatherName())) { - validationErrors.add("- Father's Name is invalid: " + dto.getFatherName()); + validationErrors.add("- Father's Name is invalid: " + dto.getFatherName()+ " First name has to contain alphabetic values only"); } if (!DataValidation.isCourseNameValid(dto.getCourse_name())) { - validationErrors.add("- Course Name is invalid: " + dto.getCourse_name()); + validationErrors.add("- Course Name is invalid: " + dto.getCourse_name()+ " Course name has to contain alpha-numeric values, eg:ANM1\n"); } if (!DataValidation.isExamCycleValid(dto.getExamCycle_name())) { - validationErrors.add("- Exam Cycle is invalid: " + dto.getExamCycle_name()); + validationErrors.add("- Exam Cycle is invalid: " + dto.getExamCycle_name()+ " Exam cycle name has to contain alpha-numeric values, eg: Fall 2023\n"); } if (!DataValidation.isExamValid(dto.getExam_name())) { - validationErrors.add("- Exam is invalid: " + dto.getExam_name()); + validationErrors.add("- Exam is invalid: " + dto.getExam_name()+ " Exam name has to contain alpha-numeric values, eg:Microbiology_1\n"); } if (!DataValidation.isMarksValid(dto.getInternalMarks())) { - validationErrors.add("- Internal Marks is invalid: " + dto.getInternalMarks()); + validationErrors.add("- Internal Marks is invalid: " + dto.getInternalMarks() + " Marks has to be with in 0 and 100"); } if (!DataValidation.isPassingMarksValid(dto.getPassingInternalMarks())) { - validationErrors.add("- Passing Internal Marks is invalid: " + dto.getPassingInternalMarks()); + validationErrors.add("- Passing Internal Marks is invalid: " + dto.getPassingInternalMarks() + " Marks has to be with in 0 and 100"); } if (!DataValidation.isMarksValid(dto.getInternalMarksObtained())) { - validationErrors.add("- Internal Marks Obtained is invalid: " + dto.getInternalMarksObtained()); + validationErrors.add("- Internal Marks Obtained is invalid: " + dto.getInternalMarksObtained()+ " Marks has to be with in 0 and 100"); } if (!DataValidation.isMarksValid(dto.getPracticalMarks())) { - validationErrors.add("- Practical Marks is invalid: " + dto.getPracticalMarks()); + validationErrors.add("- Practical Marks is invalid: " + dto.getPracticalMarks() + " Marks has to be with in 0 and 100"); } if (!DataValidation.isPassingMarksValid(dto.getPassingPracticalMarks())) { - validationErrors.add("- Passing Practical Marks is invalid: " + dto.getPassingPracticalMarks()); + validationErrors.add("- Passing Practical Marks is invalid: " + dto.getPassingPracticalMarks() + " Marks has to be with in 0 and 100"); } if (!DataValidation.isPassingMarksValid(dto.getPracticalMarksObtained())) { - validationErrors.add("- Practical Marks Obtained is invalid: " + dto.getPracticalMarksObtained()); + validationErrors.add("- Practical Marks Obtained is invalid: " + dto.getPracticalMarksObtained() + " Marks has to be with in 0 and 100"); } if (!DataValidation.isMarksValid(dto.getOtherMarks())) { - validationErrors.add("- Other Marks is invalid: " + dto.getOtherMarks()); + validationErrors.add("- Other Marks is invalid: " + dto.getOtherMarks() + " Marks has to be with in 0 and 100"); } if (!DataValidation.isPassingMarksValid(dto.getPassingOtherMarks())) { - validationErrors.add("- Passing Other Marks is invalid: " + dto.getPassingOtherMarks()); + validationErrors.add("- Passing Other Marks is invalid: " + dto.getPassingOtherMarks() + " Marks has to be with in 0 and 100"); } if (!DataValidation.isMarksValid(dto.getOtherMarksObtained())) { - validationErrors.add("- Other Marks Obtained is invalid: " + dto.getOtherMarksObtained()); - } - if (!DataValidation.isGradeValid(dto.getGrade())) { - validationErrors.add("- Grade is invalid: " + dto.getGrade()); - } - if (!DataValidation.isResultValid(dto.getResult())) { - validationErrors.add("- Result is invalid: " + dto.getResult()); + validationErrors.add("- Other Marks Obtained is invalid: " + dto.getOtherMarksObtained() + " Marks has to be with in 0 and 100"); } - if (!validationErrors.isEmpty()) { - isValid = false; - } else { - StudentResult entity = getStudentResult(dto,instituteId); + if (validationErrors.isEmpty()) { + StudentResult entity = getStudentResult(dto, instituteId); entityList.add(entity); + } else { + isValid = false; } } } - if (!validationErrors.isEmpty()) { - StringBuilder errorMessage = new StringBuilder("Validation failed. The following fields contain invalid values:\n"); - for (String validationError : validationErrors) { - errorMessage.append(validationError).append("\n"); - } - throw new ValidationException(isValid, errorMessage.toString()); + ValidationResultDto resultDto = new ValidationResultDto(); + if (!validationErrors.isEmpty()) { + resultDto.setValid(false); + resultDto.setValidationErrors(validationErrors); + } else { + resultDto.setValid(true); + repository.saveAll(entityList); + resultDto.setSavedEntities(entityList); } - repository.saveAll(entityList); - return isValid; + return resultDto; } - public boolean convertResultDtoListToEntitiesExternalMarks(List<StudentResult> dtoList, StudentResultRepository repository) throws ValidationException { + public ValidationResultDto convertResultDtoListToEntitiesExternalMarks(List<StudentResult> dtoList, StudentResultRepository repository) { List<StudentResult> entityList = new ArrayList<>(); - boolean isValid = true; List<String> validationErrors = new ArrayList<>(); for (StudentResult dto : dtoList) { boolean isDuplicate = checkIfDataExists(dto); - + //fetch data from student_exam_registration and set the flag there, if the record is not found break and return data invalid if (isDuplicate) { if (!DataValidation.isFirstNameValid(dto.getFirstName())) { - validationErrors.add("- First Name is invalid: " + dto.getFirstName()); + validationErrors.add("- First Name is invalid: " + dto.getFirstName() + " First name has to contain alphabetic values only"); } if (!DataValidation.isLastNameValid(dto.getLastName())) { - validationErrors.add("- Last Name is invalid: " + dto.getLastName()); + validationErrors.add("- Last Name is invalid: " + dto.getLastName() + " Last name has to contain alphabetic values only"); } if (!DataValidation.isEnrollmentNumberValid(dto.getEnrollmentNumber())) { - validationErrors.add("- Enrollment Number is invalid: " + dto.getEnrollmentNumber()); + validationErrors.add("- Enrollment Number is invalid: " + dto.getEnrollmentNumber() + " Enrollment number has to contain numerical values prefixed with EN"); } - if (!DataValidation.isMarksValid(dto.getOtherMarks())) { - validationErrors.add("- External marks is invalid: " + dto.getOtherMarks()); + if (!DataValidation.isMarksValid(dto.getExternalMarks())) { + validationErrors.add("- External marks is invalid: " + dto.getExternalMarks() + " Marks have to be within 0 and 100"); } - if (!DataValidation.isPassingMarksValid(dto.getPassingOtherMarks())) { - validationErrors.add("- Passing External Marks is invalid: " + dto.getPassingOtherMarks()); + if (!DataValidation.isPassingMarksValid(dto.getPassingExternalMarks())) { + validationErrors.add("- Passing External Marks is invalid: " + dto.getPassingExternalMarks() + " Marks have to be within 0 and 100"); } - if (!DataValidation.isMarksValid(dto.getOtherMarksObtained())) { - validationErrors.add("- External Marks Obtained is invalid: " + dto.getOtherMarksObtained()); - } - - - if (!validationErrors.isEmpty()) { - isValid = false; - } else { - // Search for an existing entity based on first name, last name, and enrollment number - StudentResult existingEntity = repository.findByFirstNameAndLastNameAndEnrollmentNumber(dto.getFirstName(), dto.getLastName(), dto.getEnrollmentNumber()); -// List<StudentResult> marks = calculateResult(dto.getInternalMarks(),dto.getPassingInternalMarks(),dto.getInternalMarksObtained(),dto.getPracticalMarks(), -// dto.getPassingPracticalMarks(),dto.getPracticalMarksObtained(),dto.getExternalMarks(),dto.getPassingExternalMarks(),dto.getExternalMarksObtained()); - if (existingEntity != null) { - // Update the specific columns - existingEntity.setExternalMarks(dto.getExternalMarks()); - existingEntity.setPassingExternalMarks(dto.getPassingExternalMarks()); - existingEntity.setExternalMarksObtained(dto.getExternalMarksObtained()); -// existingEntity.setTotalMarks(marks.get(0).getTotalMarks()); -// existingEntity.setPassingTotalMarks(marks.get(0).getPassingTotalMarks()); -// existingEntity.setTotalMarksObtained(marks.get(0).getTotalMarksObtained()); - } else { - throw new ValidationException(false, "Record not found for: " + dto.getFirstName() + " " + dto.getLastName() + " Enrollment Number: " + dto.getEnrollmentNumber()); - } + if (!DataValidation.isMarksValid(dto.getExternalMarksObtained())) { + validationErrors.add("- External Marks Obtained is invalid: " + dto.getExternalMarksObtained() + " Marks have to be within 0 and 100"); } } - } - if (!validationErrors.isEmpty()) { - StringBuilder errorMessage = new StringBuilder("Validation failed. The following fields contain invalid values:\n"); - - for (String validationError : validationErrors) { - errorMessage.append(validationError).append("\n"); + if (validationErrors.isEmpty()) { + StudentResult existingEntity = repository.findByFirstNameAndLastNameAndEnrollmentNumber(dto.getFirstName(), dto.getLastName(), dto.getEnrollmentNumber()); + List<StudentResult> marks = calculateResult(existingEntity.getInternalMarks(), existingEntity.getPassingInternalMarks(), existingEntity.getInternalMarksObtained(), existingEntity.getPracticalMarks(), + existingEntity.getPassingPracticalMarks(), existingEntity.getPracticalMarksObtained(), dto.getExternalMarks(), dto.getPassingExternalMarks(), dto.getExternalMarksObtained()); + + existingEntity.setExternalMarks(dto.getExternalMarks()); + existingEntity.setPassingExternalMarks(dto.getPassingExternalMarks()); + existingEntity.setExternalMarksObtained(dto.getExternalMarksObtained()); + existingEntity.setFinalMarkFlag(true); + existingEntity.setTotalMarks(marks.get(0).getTotalMarks()); + existingEntity.setPassingTotalMarks(marks.get(0).getPassingTotalMarks()); + existingEntity.setTotalMarksObtained(marks.get(0).getTotalMarksObtained()); + existingEntity.setResult(marks.get(0).getResult()); + existingEntity.setGrade(marks.get(0).getGrade()); + + entityList.add(existingEntity); } - throw new ValidationException(isValid, errorMessage.toString()); } - repository.saveAll(entityList); - return isValid; + ValidationResultDto resultDto = new ValidationResultDto(); + if (!validationErrors.isEmpty()) { + resultDto.setValid(false); + resultDto.setValidationErrors(validationErrors); + } else { + resultDto.setValid(true); + repository.saveAll(entityList); + resultDto.setSavedEntities(entityList); + } + return resultDto; } + private List<StudentResult> calculateResult( Integer internalMarks, Integer passingInternalMarks, Integer internalMarksObtained, Integer practicalMarks, Integer passingPracticalMarks, Integer practicalMarksObtained, @@ -702,7 +695,11 @@ public class DataImporterService { private StudentResult getStudentResult(StudentResult dto, Long instituteId) { StudentResult entity = new StudentResult(); - Institute institute = instituteRepository.findById(instituteId).orElse(null); + +// Course course = courseRepository.findByCourseNameIgnoreCase(dto.getCourse_name()).orElseThrow(); +// Exam exam = examRepository.findByExamName(dto.getExam_name()).orElseThrow(); +// ExamCycle examCycle = cycleRepository.findByExamCycleName(dto.getExamCycle_name()); +// Student student = studentRepository.findByEnrollmentNumber(dto.getEnrollmentNumber()).orElseThrow(); entity.setFirstName(dto.getFirstName()); entity.setLastName(dto.getLastName()); @@ -721,14 +718,17 @@ public class DataImporterService { entity.setOtherMarks(dto.getOtherMarks()); entity.setPassingOtherMarks(dto.getPassingOtherMarks()); entity.setOtherMarksObtained(dto.getOtherMarksObtained()); - entity.setGrade(dto.getGrade()); - entity.setResult(dto.getResult()); - entity.setInstituteId(dto.getInstituteId()); + entity.setInternalMarkFlag(true); + entity.setInstituteId(instituteId); +// entity.setCourse(course); +// entity.setExam(exam); +// entity.setExamCycle(examCycle); +// entity.setStudent(student); return entity; } private boolean checkIfDataExists(StudentResult dto) { - return studentResultRepository.existsByEnrollmentNumber(dto.getEnrollmentNumber()); + return studentResultRepository.existsByEnrollmentNumberAndFirstNameAndLastName(dto.getEnrollmentNumber(),dto.getFirstName(),dto.getLastName()); } private boolean checkIfDataExists(AttendanceRecord dto) { diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/ExamCycleService.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/ExamCycleService.java index 9ab5c32472c231b021b9cd9a5ed5112eeb5c6941..318f40884ad4889267c76554e6fcb37c7096040c 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/ExamCycleService.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/ExamCycleService.java @@ -23,6 +23,7 @@ import org.springframework.web.multipart.MultipartFile; import javax.validation.ConstraintViolationException; import java.sql.ResultSet; import java.sql.SQLException; +import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.format.DateTimeFormatter; @@ -366,24 +367,24 @@ public class ExamCycleService { List<ExamCycleDTO> examCycleDTOs = Collections.EMPTY_LIST; StringBuilder stringBuilder = new StringBuilder("select * from exam_cycle where date_part('year', start_date) = '") .append(searchExamCycleDTO.getStartYear()).append("' and obsolete = 0 "); - try{ - if(searchExamCycleDTO.getCourseId() != null && !searchExamCycleDTO.getCourseId().isBlank()) { + try { + if (searchExamCycleDTO.getCourseId() != null && !searchExamCycleDTO.getCourseId().isBlank()) { stringBuilder.append(" and course_id = '").append(searchExamCycleDTO.getCourseId()).append("' "); } - if(searchExamCycleDTO.getEndYear() != null && searchExamCycleDTO.getEndYear() > 0) { + if (searchExamCycleDTO.getEndYear() != null && searchExamCycleDTO.getEndYear() > 0) { stringBuilder.append("and date_part('year', end_date) <= '").append(searchExamCycleDTO.getEndYear()).append("' "); } List<ExamCycle> examCycles = jdbcTemplate.query(stringBuilder.toString(), new ResultSetExtractor<List<ExamCycle>>() { @Override public List<ExamCycle> extractData(ResultSet rs) throws SQLException, DataAccessException { List<ExamCycle> examCycleList = new ArrayList<>(); - while(rs.next()) { + while (rs.next()) { examCycleList.add(ExamCycle.builder().examCycleName(rs.getString("exam_cycle_name")).id(rs.getLong("id")).build()); } return examCycleList; } }); - if(examCycles != null && !examCycles.isEmpty()) { + if (examCycles != null && !examCycles.isEmpty()) { examCycleDTOs = examCycles.stream().map(record -> toDTO(record)).collect(Collectors.toList()); } response.put(Constants.MESSAGE, Constants.SUCCESS); @@ -398,10 +399,10 @@ public class ExamCycleService { } private void validateSearchExamCyclePayload(SearchExamCycleDTO searchExamCycleDTO) { - if(searchExamCycleDTO == null) { + if (searchExamCycleDTO == null) { throw new InvalidRequestException(Constants.INVALID_REQUEST_ERROR_MESSAGE); } - if(searchExamCycleDTO.getStartYear() == null || searchExamCycleDTO.getStartYear() <= 0) { + if (searchExamCycleDTO.getStartYear() == null || searchExamCycleDTO.getStartYear() <= 0) { throw new InvalidRequestException(Constants.MISSING_SEARCH_PARAM_START_ACADEMIC_YEAR); } } @@ -444,5 +445,9 @@ public class ExamCycleService { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); } } - -} \ No newline at end of file + public List<ExamCycle> getExamCyclesByExamCycleAndCourse(Long instituteId) { + List<Course> courses = courseRepository.findAllByInstituteId(instituteId); + LocalDate currentDate = LocalDate.now(); + return repository.findByCourseInAndEndDateAfter(courses, currentDate); + } +} diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/FeeService.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/FeeService.java index 658f1969f2b7295afb8c454690bda6bd00ff83fc..2b854bde92f3afd01edbd4234f67dc42fbd5561b 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/FeeService.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/FeeService.java @@ -20,4 +20,6 @@ public interface FeeService { void updateExamFeeStatusByRefNo(String refNo); List<StudentExamFeeDto> getStudentDetailsByRefNo(String refNo); + + List<StudentExamFeeDto> getStudentDetailsByExamCycleIdAndInstituteId(Long examCycleId, Long instituteId); } diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/HallTicketService.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/HallTicketService.java index 6dc15384c6efa332ade93598f3f04f2a8b8040da..3a6ea963ed640588f90dba24b89a6e4b24dd34a7 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/HallTicketService.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/HallTicketService.java @@ -1,8 +1,6 @@ package com.tarento.upsmf.examsAndAdmissions.service; import com.google.cloud.storage.Blob; -import com.google.cloud.storage.BlobId; -import com.tarento.upsmf.examsAndAdmissions.enums.ApprovalStatus; import com.tarento.upsmf.examsAndAdmissions.enums.DocumentType; import com.tarento.upsmf.examsAndAdmissions.enums.HallTicketStatus; import com.tarento.upsmf.examsAndAdmissions.model.*; @@ -19,11 +17,11 @@ import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.font.PDType1Font; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.InputStreamResource; import org.springframework.core.io.Resource; -import org.springframework.core.io.UrlResource; -import org.springframework.http.*; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.client.RestTemplate; @@ -32,13 +30,9 @@ import org.springframework.web.multipart.MultipartFile; import javax.persistence.EntityManager; import javax.persistence.criteria.*; import java.io.ByteArrayOutputStream; -import java.io.FileNotFoundException; import java.io.IOException; -import java.net.MalformedURLException; +import java.net.URISyntaxException; import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.LocalDate; @@ -172,6 +166,29 @@ public class HallTicketService { response.setResponseCode(HttpStatus.OK); return response; } + + public ResponseDto getHallTicketForStudentByStudentIdAndExamCycleId(Long id, Long examCycleId) { + ResponseDto response = new ResponseDto(Constants.API_HALLTICKET_GET_BY_ID); + + List<StudentExamRegistration> registrationOptional = studentExamRegistrationRepository.findAllByStudent_IdAndExam_Id(id, examCycleId); + if (registrationOptional.isEmpty()) { + setErrorResponse(response, "STUDENT_NOT_FOUND", "No student record found for the provided details.", HttpStatus.NOT_FOUND); + return response; + } + + List<String> hallTickets = new ArrayList<>(); + registrationOptional.stream().filter(path -> !path.getHallTicketPath().isBlank()).forEach(ticket -> hallTickets.add(ticket.getHallTicketPath())); + if (hallTickets == null || hallTickets.isEmpty()) { + setErrorResponse(response, "HALL_TICKET_NOT_GENERATED", "Hall ticket not generated for this student.", HttpStatus.NOT_FOUND); + return response; + } + + response.put(Constants.MESSAGE, Constants.SUCCESSMESSAGE); + response.put(Constants.RESPONSE, hallTickets); // Sending the hall ticket as a resource + response.setResponseCode(HttpStatus.OK); + return response; + } + public ResponseDto getHallTicketBlobResourcePath(Long id, String dateOfBirth) throws Exception { ResponseDto hallTicketResponse = getHallTicketForStudent(id, dateOfBirth); @@ -200,6 +217,41 @@ public class HallTicketService { } } + public ResponseDto getHallTicketBlobResourcePathByStudentId(Long studentId, Long examCycleId) throws Exception { + ResponseDto hallTicketResponse = getHallTicketForStudentByStudentIdAndExamCycleId(studentId, examCycleId); + + if (hallTicketResponse.getResponseCode().is2xxSuccessful()) { + List<String> hallTicketPaths = (List) hallTicketResponse.getResult().get(Constants.RESPONSE); + List<URL> signedUrls = new ArrayList<>(); + hallTicketPaths.stream().forEach(ticket -> { + try { + Blob blob = fileStorageService.getBlobFromGCP(ticket); + if (blob != null && blob.exists()) { + // Generate a signed URL for direct download + URL signedUrl = blob.signUrl(15, TimeUnit.MINUTES); + signedUrls.add(signedUrl); + } + } catch (IOException | URISyntaxException e) { + log.error("Error in converting to blob"); + } + }); + if (signedUrls.isEmpty()) { + ResponseDto response = new ResponseDto(Constants.API_HALLTICKET_GET_BY_ID); + ResponseDto.setErrorResponse(response, "BLOB_NOT_FOUND", "Error fetching hall ticket from storage.", HttpStatus.INTERNAL_SERVER_ERROR); + return response; + } + hallTicketResponse.getResult().put(Constants.RESPONSE, signedUrls); // use the signed URL + return hallTicketResponse; + + } else if (hallTicketResponse.getResponseCode() == HttpStatus.NOT_FOUND) { + return hallTicketResponse; // Directly return the 404 response if the record isn't found + } else { + ResponseDto response = new ResponseDto(Constants.API_HALLTICKET_GET_BY_ID); + ResponseDto.setErrorResponse(response, "REQUEST_ERROR", "Error processing request: " + hallTicketResponse.getError().getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + return response; + } + } + public ResponseDto requestHallTicketDataCorrection(Long studentId, String updatedFirstName, String updatedLastName, diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/StudentExamRegistrationService.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/StudentExamRegistrationService.java index fed722818be4ffb1ee0a8db492a51e7353c30210..fa8a190c7b19a3ff07b53183497a8e6299697cb0 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/StudentExamRegistrationService.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/StudentExamRegistrationService.java @@ -242,9 +242,10 @@ public class StudentExamRegistrationService { dto.setEnrollmentNumber(registration.getStudent().getEnrollmentNumber()); dto.setCourseName(registration.getStudent().getCourse().getCourseName()); dto.setSession(registration.getStudent().getSession()); + dto.setId(registration.getStudent().getId()); Exam examForRegistration = registration.getExam(); - List<ExamInfoDto> exams = Collections.singletonList(new ExamInfoDto(examForRegistration.getId(), examForRegistration.getExamName())); + List<ExamInfoDto> exams = Collections.singletonList(new ExamInfoDto(examForRegistration.getId(), examForRegistration.getExamName(), registration.isFeesPaid(), examForRegistration.getAmount())); dto.setExams(exams); dto.setNumberOfExams(1); @@ -281,10 +282,10 @@ public class StudentExamRegistrationService { dto.setNumberOfExams(unregisteredExams.size()); dto.setId(student.getId()); List<ExamInfoDto> exams = Optional.of(unregisteredExams.stream() - .map(exam -> new ExamInfoDto(exam.getId(), exam.getExamName())) + .map(exam -> new ExamInfoDto(exam.getId(), exam.getExamName(),false, exam.getAmount())) .collect(Collectors.toList())) .filter(list -> !list.isEmpty()) - .orElseGet(() -> Collections.singletonList(new ExamInfoDto(0L, null))); + .orElseGet(() -> Collections.singletonList(new ExamInfoDto(0L, null, false, 0.00))); dto.setExams(exams); resultDTOs.add(dto); diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/StudentResultService.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/StudentResultService.java index 631addf786268cffae1ce01cd037446811d1ef0a..b94a0d23f60033df014d564ecdb10624c06503e7 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/StudentResultService.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/StudentResultService.java @@ -9,7 +9,9 @@ import com.tarento.upsmf.examsAndAdmissions.repository.*; import com.tarento.upsmf.examsAndAdmissions.util.Constants; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; -import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.ss.usermodel.Row; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.codehaus.jettison.json.JSONArray; @@ -19,8 +21,6 @@ import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; -import java.math.BigDecimal; -import java.time.LocalDate; import java.util.*; import java.util.stream.Collectors; @@ -33,6 +33,8 @@ public class StudentResultService { @Autowired private StudentRepository studentRepository; + @Autowired + private InstituteRepository instituteRepository; @Autowired private CourseRepository courseRepository; @@ -404,9 +406,9 @@ public class StudentResultService { return response; } - public ResponseDto findByEnrollmentNumberAndDateOfBirth(String enrollmentNumber, LocalDate dateOfBirth, Long examCycleId) { + public ResponseDto findByEnrollmentNumberAndDateOfBirth(String enrollmentNumber, Long examCycleId) { ResponseDto response = new ResponseDto(Constants.API_FIND_BY_ENROLLMENT_NUMBER_AND_DOB); - List<StudentResult> studentResultList = studentResultRepository.findByStudent_EnrollmentNumberAndStudent_DateOfBirthAndExamCycle_IdAndPublished(enrollmentNumber, dateOfBirth, examCycleId, true); + List<StudentResult> studentResultList = studentResultRepository.findByStudent_EnrollmentNumberAndExamCycle_IdAndPublished(enrollmentNumber, examCycleId, true); if (!studentResultList.isEmpty()) { StudentResultDTO studentResultDTO = mapToDTO(studentResultList); @@ -592,32 +594,35 @@ public class StudentResultService { switch (fileType.toLowerCase()) { case Constants.CSV: - jsonArray = dataImporterService.csvToJson(file,columnConfig); + jsonArray = dataImporterService.csvToJson(file, columnConfig); break; case Constants.EXCEL: jsonArray = dataImporterService.excelToJson(file); break; default: - // Handle unsupported file type return ResponseDto.setErrorResponse(response, "UNSUPPORTED_FILE_TYPE", "Unsupported file type", HttpStatus.BAD_REQUEST); } List<StudentResult> dtoList = dataImporterService.convertJsonToDtoList(jsonArray, StudentResult.class); - boolean success = dataImporterService.convertResultDtoListToEntities(dtoList, studentResultRepository, instituteId); + ValidationResultDto validationResult = dataImporterService.convertResultDtoListToEntities(dtoList, studentResultRepository, instituteId); - if (success) { - response.put(Constants.MESSAGE, "File processed successfully."); + if (validationResult.isValid()) { + response.put(Constants.MESSAGE, "Bulk upload success"); + response.put("Data",validationResult.getSavedEntities()); response.setResponseCode(HttpStatus.OK); } else { - return ResponseDto.setErrorResponse(response, "FILE_PROCESSING_FAILED", "File processing failed.", HttpStatus.INTERNAL_SERVER_ERROR); + if (!validationResult.getValidationErrors().isEmpty()) { + response.put("validationErrors", validationResult.getValidationErrors()); + response.setResponseCode(HttpStatus.BAD_REQUEST); + } else { + return ResponseDto.setErrorResponse(response, "INTERNAL_ERROR", "An unexpected error occurred.", HttpStatus.INTERNAL_SERVER_ERROR); + } } + return response; // Return the ResponseDto without using ResponseEntity } catch (Exception e) { - log.error("Error processing bulk result upload", e); - return ResponseDto.setErrorResponse(response, "INTERNAL_ERROR", "An unexpected error occurred: "+ e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + return ResponseDto.setErrorResponse(response, "INTERNAL_ERROR", "An unexpected error occurred.", HttpStatus.INTERNAL_SERVER_ERROR); } - - return response; } public ResponseDto processBulkResultUploadWithExternals(MultipartFile file, String fileType) { @@ -640,21 +645,24 @@ public class StudentResultService { String[] selectedColumns = { "First Name", "Last Name", "Enrolment Number","External Marks", "Passing External Marks", "External Marks Obtained" }; JSONArray filteredJsonArray = dataImporterService.filterColumns(jsonArray, selectedColumns); List<StudentResult> dtoList = dataImporterService.convertJsonToDtoList(filteredJsonArray, StudentResult.class); - boolean success = dataImporterService.convertResultDtoListToEntitiesExternalMarks(dtoList, studentResultRepository); + ValidationResultDto validationResult = dataImporterService.convertResultDtoListToEntitiesExternalMarks(dtoList, studentResultRepository); - if (success) { - response.put(Constants.MESSAGE, "File processed successfully."); + if (validationResult.isValid()) { + response.put(Constants.MESSAGE, "Bulk upload success"); + response.put("Data",validationResult.getSavedEntities()); response.setResponseCode(HttpStatus.OK); } else { - return ResponseDto.setErrorResponse(response, "FILE_PROCESSING_FAILED", "File processing failed.", HttpStatus.INTERNAL_SERVER_ERROR); + if (!validationResult.getValidationErrors().isEmpty()) { + response.put("validationErrors", validationResult.getValidationErrors()); + response.setResponseCode(HttpStatus.BAD_REQUEST); + } else { + return ResponseDto.setErrorResponse(response, "INTERNAL_ERROR", "An unexpected error occurred.", HttpStatus.INTERNAL_SERVER_ERROR); + } } - + return response; } catch (Exception e) { - log.error("Error processing bulk result upload", e); - return ResponseDto.setErrorResponse(response, "INTERNAL_ERROR", "An unexpected error occurred: "+ e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + return ResponseDto.setErrorResponse(response, "INTERNAL_ERROR", "An unexpected error occurred.", HttpStatus.INTERNAL_SERVER_ERROR); } - - return response; } @@ -697,24 +705,33 @@ public class StudentResultService { } public ResponseDto getExamResultsByExamCycle(Long examCycle) { ResponseDto response = new ResponseDto(Constants.API_EXAM_CYCLE_MANAGE_RESULTS); - - List<StudentExamRegistration> results = studentExamRegistrationRepository.findByExamCycleId(examCycle); + String examCycleName = examCycleRepository.getExamCycleNameById(examCycle); + List<StudentResult> results = studentResultRepository.findByExamCycleName(examCycleName); if (results == null || results.isEmpty()) { ResponseDto.setErrorResponse(response, "RECORD_NOT_FOUND", "No record found for the given exam cycle.", HttpStatus.NOT_FOUND); return response; } + Map<Long, ProcessedResultDto> processedResults = getProcessedResults(results); + + response.put(Constants.MESSAGE, "Results fetched successfully."); + response.put(Constants.RESPONSE, new ArrayList<>(processedResults.values())); + response.setResponseCode(HttpStatus.OK); + return response; + } + + private Map<Long, ProcessedResultDto> getProcessedResults(List<StudentResult> results) { Map<Long, ProcessedResultDto> processedResults = new HashMap<>(); - for (StudentExamRegistration result : results) { - Institute institute = result.getStudent().getInstitute(); - Long instituteId = institute.getId(); + for (StudentResult result : results) { + Long instituteId = result.getInstituteId(); + Institute institute = instituteRepository.findById(instituteId).orElseThrow(); ProcessedResultDto instituteResult = processedResults.computeIfAbsent(instituteId, id -> { ProcessedResultDto dto = new ProcessedResultDto(); dto.setInstituteId(instituteId); dto.setInstituteName(institute.getInstituteName()); - dto.setCourse(result.getStudent().getCourse().getCourseName()); + dto.setCourse(result.getCourse_name()); return dto; }); instituteResult.setHasFinalMarks(result.isInternalMarkFlag()); @@ -722,16 +739,14 @@ public class StudentResultService { instituteResult.setHasRevisedFinalMarks(result.isRevisedFinalMarkFlag()); } - - response.put(Constants.MESSAGE, "Results fetched successfully."); - response.put(Constants.RESPONSE, new ArrayList<>(processedResults.values())); - response.setResponseCode(HttpStatus.OK); - return response; + return processedResults; } public ResponseDto getMarksByInstituteAndExamCycle(Long examCycle, Long exam, Long institute) { ResponseDto response = new ResponseDto(Constants.API_SINGLE_EXAM_MARK); - List<StudentResult> studentResults = studentResultRepository.findByExamCycleAndExamAndInstitute(examCycle, exam, institute); + String examCycleName = examCycleRepository.getExamCycleNameById(examCycle); + String examName = examRepository.getExamNameById(exam); + List<StudentResult> studentResults = studentResultRepository.findByExamCycleNameAndExamNameAndInstitute(examCycleName, examCycleName, institute); // If no results found, return a not found response. if(studentResults.isEmpty()) { @@ -775,7 +790,7 @@ public class StudentResultService { dto.setLastDateToUploadInternalMarks(exam.getLastDateToUploadMarks()); // Now check for student results for this exam and institute - List<StudentResult> resultsForExam = studentResultRepository.findByExamIdAndInstituteId(exam.getId(), instituteId); + List<StudentResult> resultsForExam = studentResultRepository.findByExamNameAndInstituteId(exam.getExamName(), instituteId); if (!resultsForExam.isEmpty()) { // If we find any student result records, it means internal marks have been uploaded @@ -793,12 +808,12 @@ public class StudentResultService { response.put(Constants.RESPONSE, dtos); response.setResponseCode(HttpStatus.OK); } else { - ResponseDto.setErrorResponse(response, "NO_EXAMS_FOUND", "No exams found for the provided exam cycle.", HttpStatus.NOT_FOUND); + return ResponseDto.setErrorResponse(response, "NO_EXAMS_FOUND", "No exams found for the provided exam cycle.", HttpStatus.NOT_FOUND); } } catch (Exception e) { // Handle any unexpected errors that might occur during the process. - ResponseDto.setErrorResponse(response, "INTERNAL_SERVER_ERROR", e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + return ResponseDto.setErrorResponse(response, "INTERNAL_SERVER_ERROR", e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); } return response; diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/StudentService.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/StudentService.java index edb2e5e7116d9dd9f677744b3e39ec23ea23462a..0f66968d1eadaca7bbd30509c5d141bd5e8ba018 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/StudentService.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/StudentService.java @@ -1,12 +1,14 @@ package com.tarento.upsmf.examsAndAdmissions.service; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.auth.oauth2.ServiceAccountCredentials; import com.google.cloud.storage.*; -import com.tarento.upsmf.examsAndAdmissions.enums.ApprovalStatus; +import com.tarento.upsmf.examsAndAdmissions.controller.UserController; import com.tarento.upsmf.examsAndAdmissions.enums.VerificationStatus; import com.tarento.upsmf.examsAndAdmissions.model.*; -import com.tarento.upsmf.examsAndAdmissions.model.dto.InstituteDTO; -import com.tarento.upsmf.examsAndAdmissions.model.dto.StudentDto; +import com.tarento.upsmf.examsAndAdmissions.model.dto.*; import com.tarento.upsmf.examsAndAdmissions.repository.CourseRepository; import com.tarento.upsmf.examsAndAdmissions.repository.InstituteRepository; import com.tarento.upsmf.examsAndAdmissions.repository.StudentRepository; @@ -18,6 +20,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.PropertySource; import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; @@ -46,6 +49,12 @@ public class StudentService { @Autowired private EntityManager entityManager; + @Autowired + private IntegrationService integrationService; + + @Autowired + private ObjectMapper mapper; + @Value("${gcp.config.file.path}") private String gcpConfigFilePath; @@ -383,6 +392,34 @@ public class StudentService { return studentRepository.save(student); } + private String createStudentLoginInKeycloak(Student student) throws Exception { + if (student.getEmailId() == null || student.getEmailId().isEmpty()) { + throw new RuntimeException("Email id is mandatory"); + } + Map<String, String> attributes = new HashMap<>(); + attributes.put("module", "exam"); + attributes.put("departmentName", String.valueOf(-1)); + attributes.put("phoneNumber", student.getMobileNo()); + attributes.put("Role", "exams_student"); + attributes.put("studentId", String.valueOf(student.getId())); + + CreateUserDto createUserDto = CreateUserDto.builder() + .firstName(student.getFirstName()) + .lastName(student.getSurname()) + .email(student.getEmailId()) + .username(student.getEmailId()) + .attributes(attributes) + .build(); + + ResponseEntity<User> response = integrationService.createUser(createUserDto); + log.info("Create user Response during verify - {}", response); + if (response.getStatusCode() == HttpStatus.OK) { + User userContent = response.getBody(); + return userContent.getId(); + } + throw new RuntimeException("Exception occurred during creating user in keycloak"); + } + public ResponseDto verifyStudent(Long studentId, VerificationStatus status, String remarks, String verifierUserId) { ResponseDto response = new ResponseDto(Constants.API_VERIFY_STUDENT); @@ -402,6 +439,8 @@ public class StudentService { if (status == VerificationStatus.VERIFIED) { String enrollmentNumber = "EN" + LocalDate.now().getYear() + student.getInstitute().getId() + student.getId(); student.setEnrollmentNumber(enrollmentNumber); + String keycloakId = createStudentLoginInKeycloak(student); + student.setKeycloakId(keycloakId); } else if (status == VerificationStatus.REJECTED) { student.setRequiresRevision(true); } @@ -456,6 +495,7 @@ public class StudentService { } throw new RuntimeException("Invalid file type. Supported files are PDF and Images."); } + public ResponseDto deleteStudent(Long id) { ResponseDto response = new ResponseDto(Constants.API_DELETE_STUDENT); diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/impl/AttachmentServiceImpl.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/impl/AttachmentServiceImpl.java index dc8cff6aa53ce3ec78606ca5e7461b189f52c9c5..2208843e785d6fb43672ff47abda8518c0bf96b3 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/impl/AttachmentServiceImpl.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/impl/AttachmentServiceImpl.java @@ -91,13 +91,13 @@ public class AttachmentServiceImpl implements AttachmentService { LocalTime examTime = questionPaperDetails.getExamStartTime(); String fileName = questionPaperDetails.getGcpFileName(); try { - LocalDate currentDate = LocalDate.now(); + LocalDate currentDate = LocalDate.now(ZoneId.of("Asia/Kolkata")); // Check if the current date is the same as the exam date if (currentDate.getYear() == examDate.getYear() && currentDate.getMonthValue() == examDate.getMonthValue() && currentDate.getDayOfMonth() == examDate.getDayOfMonth()) { - ZoneId zoneId = ZoneId.systemDefault(); + ZoneId zoneId = ZoneId.of("Asia/Kolkata"); ZonedDateTime currentTime = ZonedDateTime.now(zoneId); LocalTime currentLocalTime = currentTime.toLocalTime(); // Calculate the time difference diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/impl/ExamServiceImpl.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/impl/ExamServiceImpl.java index 7fe735ceb8e0e8f356985012e93fd519233ca492..e965bd3d1b5f53bba3623960ad0f5fe10513c49a 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/impl/ExamServiceImpl.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/impl/ExamServiceImpl.java @@ -107,6 +107,7 @@ public class ExamServiceImpl implements ExamService { existingExam.setExamDate(exam.getExamDate()); existingExam.setStartTime(exam.getStartTime()); existingExam.setEndTime(exam.getEndTime()); + existingExam.setAmount(exam.getAmount()); // Update auditing metadata from the payload existingExam.setModifiedBy(userId); existingExam.setModifiedOn(LocalDateTime.now()); diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/impl/FeeServiceImpl.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/impl/FeeServiceImpl.java index 9ed587ccba75b1b577b68c3c4a794b61f0b0cbc1..4e87f469788836ad8b747d55d2ef11bd7ea73229 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/impl/FeeServiceImpl.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/impl/FeeServiceImpl.java @@ -4,10 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.tarento.upsmf.examsAndAdmissions.exception.ExamFeeException; import com.tarento.upsmf.examsAndAdmissions.exception.InvalidRequestException; import com.tarento.upsmf.examsAndAdmissions.model.*; -import com.tarento.upsmf.examsAndAdmissions.model.dto.ExamFeeDto; -import com.tarento.upsmf.examsAndAdmissions.model.dto.ExamFeeSearchDto; -import com.tarento.upsmf.examsAndAdmissions.model.dto.ExamSearchResponseDto; -import com.tarento.upsmf.examsAndAdmissions.model.dto.StudentExamFeeDto; +import com.tarento.upsmf.examsAndAdmissions.model.dto.*; import com.tarento.upsmf.examsAndAdmissions.repository.*; import com.tarento.upsmf.examsAndAdmissions.service.ExamCycleService; import com.tarento.upsmf.examsAndAdmissions.service.FeeService; @@ -27,7 +24,9 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.client.RestTemplate; +import java.time.LocalDate; import java.util.*; +import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; @Service @@ -87,6 +86,9 @@ public class FeeServiceImpl implements FeeService { @Autowired private StudentExamRegistrationRepository studentExamRegistrationRepository; + @Autowired + private CourseRepository courseRepository; + /** * API to save and return payment redirect URL * @@ -128,8 +130,51 @@ public class FeeServiceImpl implements FeeService { order = Sort.Order.asc(sortKey); } PageRequest pageRequest = PageRequest.of(examFeeSearchDto.getPage(), examFeeSearchDto.getSize(), Sort.by(order)); - Page<ExamFee> examFees = examFeeRepository.findAll(pageRequest); - return ExamSearchResponseDto.builder().count(examFees.getTotalElements()).examFees(examFees.getContent()).build(); + if(examFeeSearchDto.getFilter() == null || examFeeSearchDto.getFilter().isEmpty()) { + Page<ExamFee> examFees = examFeeRepository.findAll(pageRequest); + // get total student count and total paid student count for this exam cycle and institute + List<InstituteExamFeeResponse> allFeeTransactionResponse = createAllFeeTransactionResponse(examFees.getContent()); + return ExamSearchResponseDto.builder().count(examFees.getTotalElements()).examFees(allFeeTransactionResponse).build(); + } else { + String examCycle = examFeeSearchDto.getFilter().get("examCycle"); + Page<ExamFee> examFees = examFeeRepository.findAllByExamCycleId(Long.parseLong(examCycle), pageRequest); + // get total student count and total paid student count for this exam cycle and institute + List<InstituteExamFeeResponse> allFeeTransactionResponse = createAllFeeTransactionResponse(examFees.getContent()); + return ExamSearchResponseDto.builder().count(examFees.getTotalElements()).examFees(allFeeTransactionResponse).build(); + } + } + + private List<InstituteExamFeeResponse> createAllFeeTransactionResponse(List<ExamFee> content) { + Map<Long, InstituteExamFeeResponse> instituteExamFeeResponseMap = new HashMap<>(); + content.stream().forEach(examFee -> { + if(instituteExamFeeResponseMap.containsKey(examFee.getInstitute().getId())) { + InstituteExamFeeResponse instituteExamFeeResponse = instituteExamFeeResponseMap.get(examFee.getInstitute().getId()); + updateInstituteFeeResponse(instituteExamFeeResponse, examFee); + } else { + InstituteExamFeeResponse instituteExamFeeResponse = InstituteExamFeeResponse + .builder().institute(examFee.getInstitute()).examCycle(examFee.getExamCycle()).build(); + updateInstituteFeeResponse(instituteExamFeeResponse, examFee); + instituteExamFeeResponseMap.put(examFee.getInstitute().getId(), instituteExamFeeResponse); + } + }); + return instituteExamFeeResponseMap.entrySet().stream().map(x -> x.getValue()).collect(Collectors.toList()); + } + + private void updateInstituteFeeResponse(InstituteExamFeeResponse instituteExamFeeResponse, ExamFee examFee) { + // get all students for provided reference no + List<StudentExam> allByReferenceNoAndExamCycleId = studentExamFeeRepository.findAllByReferenceNoAndExamCycleId(examFee.getReferenceNo(), examFee.getExamCycle().getId()); + if(allByReferenceNoAndExamCycleId == null || allByReferenceNoAndExamCycleId.isEmpty()) { + return; + } + long totalStudentCount = allByReferenceNoAndExamCycleId.stream().count(); + instituteExamFeeResponse.setTotalStudentsCount(instituteExamFeeResponse.getTotalStudentsCount()+totalStudentCount); + long totalPaidStudentCount = allByReferenceNoAndExamCycleId.stream().filter(student -> student.getStatus().name().equals(StudentExam.Status.PAID.name())).count(); + instituteExamFeeResponse.setTotalPaidCount(instituteExamFeeResponse.getTotalPaidCount()+totalPaidStudentCount); + AtomicReference<Double> totalPaidAmount = new AtomicReference<>(0.0); + allByReferenceNoAndExamCycleId.stream().filter(student -> student.getStatus().name().equals(StudentExam.Status.PAID.name())) + .forEach(paidStudents -> totalPaidAmount.updateAndGet(v -> v + paidStudents.getAmount())); + instituteExamFeeResponse.setTotalPaidAmount(instituteExamFeeResponse.getTotalPaidAmount()+totalPaidAmount.get()); + } private void validateGetAllPayload(ExamFeeSearchDto examFeeSearchDto) { @@ -143,6 +188,19 @@ public class FeeServiceImpl implements FeeService { if(examFeeSearchDto.getSize() <= 0) { examFeeSearchDto.setSize(50); } + if(examFeeSearchDto.getFilter() != null && !examFeeSearchDto.getFilter().isEmpty()) { + boolean isKeyMatched = examFeeSearchDto.getFilter().entrySet().stream().anyMatch(x -> x.getKey().equalsIgnoreCase("examCycle")); + if(!isKeyMatched) { + throw new ExamFeeException("Filter not supported for provided key."); + } + String examCycle = examFeeSearchDto.getFilter().get("examCycle"); + if(examCycle.isBlank()) { + throw new ExamFeeException("Invalid value for Exam Cycle."); + } + if(Long.parseLong(examCycle) <= 0) { + throw new ExamFeeException("Invalid value for Exam Cycle."); + } + } if(examFeeSearchDto.getSort() == null || examFeeSearchDto.getSort().isEmpty()) { Map<String, String> sortMap = new HashMap<>(); sortMap.put("modifiedNo", "desc"); @@ -240,15 +298,82 @@ public class FeeServiceImpl implements FeeService { }); return studentExamFeeDtoMap.values().stream().collect(Collectors.toList()); } + @Override + public List<StudentExamFeeDto> getStudentDetailsByExamCycleIdAndInstituteId(Long examCycleId, Long instituteId) { + log.info("getStudentDetailsByExamCycleIdAndInstituteId - {} | {}", examCycleId, instituteId); + if(examCycleId == null || examCycleId <= 0) { + throw new InvalidRequestException("Invalid Exam Cycle ID."); + } + if(instituteId == null || instituteId <= 0) { + throw new InvalidRequestException("Invalid Institute ID."); + } + // get transaction details from local db + List<ExamFee> examFees = examFeeRepository.findAllByInstituteIdAndExamCycleId(instituteId, examCycleId); + log.info("Exam fee list - {}", examFees); + if(examFees == null || examFees.isEmpty()) { + throw new InvalidRequestException("Error in fetching exam list for provided exam cycle and institute"); + } + // get ref nos list + List<String> refNos = new ArrayList<>(); + examFees.stream().forEach(examFee -> refNos.add(examFee.getReferenceNo())); + log.info("Exam reference no - {}", refNos); + if(refNos == null || refNos.isEmpty()) { + throw new InvalidRequestException("Error in fetching student list"); + } + // get student exams + List<StudentExam> studentExams = studentExamFeeRepository.findAllByExamCycleIdAndStatusAndReferenceNoIn(examCycleId, refNos, StudentExam.Status.PAID.name()); + if(studentExams == null || studentExams.isEmpty()) { + throw new InvalidRequestException("No Record found for Provided Reference No."); + } + log.info("student list - {}", studentExams.size()); + Map<Long, StudentExamFeeDto> studentExamFeeDtoMap = new HashMap<>(); + studentExams.stream().forEach(student -> { + if(studentExamFeeDtoMap.containsKey(student.getStudent().getId())) { + StudentExamFeeDto studentExamFeeDto = studentExamFeeDtoMap.get(student.getStudent().getId()); + if(studentExamFeeDto.getExam() != null) { + studentExamFeeDto.getExam().add(student.getExam()); + } else { + List<Exam> examList = new ArrayList<>(); + examList.add(student.getExam()); + studentExamFeeDto.setExam(examList); + } + if(studentExamFeeDto.getAmount() != null) { + double total = studentExamFeeDto.getAmount() + student.getAmount(); + studentExamFeeDto.setAmount(total); + } else { + studentExamFeeDto.setAmount(student.getAmount()); + } + } else { + List<Exam> examList = new ArrayList<>(); + examList.add(student.getExam()); + StudentExamFeeDto examFeeDto = StudentExamFeeDto.builder().exam(examList) + .student(student.getStudent()) + .amount(student.getAmount()) + .status(student.getStatus()) + .referenceNo(student.getReferenceNo()) + .build(); + studentExamFeeDtoMap.put(student.getStudent().getId(), examFeeDto); + } + }); + return studentExamFeeDtoMap.values().stream().collect(Collectors.toList()); + } private void updateStudentFeeStatusByRefNo(String refNo) { studentExamFeeRepository.updateStatusByRefNo(StudentExam.Status.PAID.name(), refNo); List<Long> studentIds = studentExamFeeRepository.getStudentIdsByRefNo(refNo); - if(studentIds!=null && !studentIds.isEmpty()) { - studentIds.stream().forEach(id -> { - studentExamRegistrationRepository.updateExamFeeByStudentId(true, id); - }); + List<StudentExam> studentExams = studentExamFeeRepository.findByReferenceNo(refNo); + if(studentExams == null || studentExams.isEmpty()) { + return; + } + ExamFee byReferenceNo = examFeeRepository.findByReferenceNo(refNo); + if(byReferenceNo == null) { + return; } + studentExams.stream().forEach(studentExam -> { + studentExamRegistrationRepository.updateExamFeeByStudentId(true, "PAYMENT DONE", "Payment Done", + studentExam.getStudent().getId(), byReferenceNo.getInstitute().getId(), + studentExam.getExamCycle().getId(), studentExam.getExam().getId()); + }); } private ResponseEntity<Transaction> getPaymentUpdate(String refNo) { @@ -270,30 +395,31 @@ public class FeeServiceImpl implements FeeService { .build(); examFee = examFeeRepository.save(examFee); // save student to exam mapping - saveStudentExamFeeMapping(referenceNumber, examFeeDto); + saveStudentExamFeeMapping(referenceNumber, examFeeDto, (ExamCycle) examCycleById.get(Constants.RESPONSE)); } - private void saveStudentExamFeeMapping(String referenceNumber, ExamFeeDto examFeeDto) { + private void saveStudentExamFeeMapping(String referenceNumber, ExamFeeDto examFeeDto, ExamCycle examCycle) { List<StudentExam> studentExams = new ArrayList<>(); // iterate through student and exam map - examFeeDto.getStudentExam().entrySet().stream().forEach(entry -> { - String studentId = entry.getKey(); - Map<Long, Double> exams = entry.getValue(); - Optional<Student> student = studentRepository.findById(Long.parseLong(studentId)); + examFeeDto.getStudentExam().stream().forEach(studentExamDto -> { + Long studentId = studentExamDto.getStudentId(); + List<ExamFeeRequestDto> exams = studentExamDto.getExam(); + Optional<Student> student = studentRepository.findById(studentId); if(student.isPresent() && exams!=null && !exams.isEmpty()) { // iterate through inner map to get exam id and corresponding fee - exams.entrySet().stream().forEach(examEntry -> { + exams.stream().forEach(examEntry -> { // get exam by id - Optional<Exam> examDetails = examRepository.findById(examEntry.getKey()); + Optional<Exam> examDetails = examRepository.findById(examEntry.getId()); //validate - if(examDetails.isPresent() && examEntry.getValue() != null && examEntry.getValue() > 0) { + if(examDetails.isPresent() && examEntry.getFee() != null && examEntry.getFee() > 0) { // create student exam object StudentExam studentExam = StudentExam.builder() .referenceNo(referenceNumber) .exam(examDetails.get()) .student(student.get()) - .amount(examEntry.getValue()) + .amount(examEntry.getFee()) .status(StudentExam.Status.INITIATED) + .examCycle(examCycle) .build(); // add to the list studentExams.add(studentExam); diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/impl/IntegrationServiceImpl.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/impl/IntegrationServiceImpl.java index ebab75ffac09aa2693cb68f0484ee8390eec90b5..a0ecf56df298bc44d3319d9daed79cbe724aa066 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/impl/IntegrationServiceImpl.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/impl/IntegrationServiceImpl.java @@ -18,6 +18,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.*; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.mail.javamail.JavaMailSender; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; @@ -53,6 +55,9 @@ public class IntegrationServiceImpl implements IntegrationService { @Autowired private RedisUtil redisUtil; + @Autowired + private JavaMailSender javaMailSender; + private ResponseEntity<String> getUserDetailsFromKeycloak(ResponseEntity response, ObjectMapper mapper) throws Exception { String userContent = response.getBody().toString(); @@ -241,6 +246,10 @@ public class IntegrationServiceImpl implements IntegrationService { } } String generatePassword = validateAndCreateDefaultPassword(user); + // setting enable value as true + user.setEnabled(true); + // setting EmailVerified value as false + user.setEmailVerified(false); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); JsonNode jsonNodeObject = mapper.convertValue(user, JsonNode.class); @@ -275,6 +284,8 @@ public class IntegrationServiceImpl implements IntegrationService { if (getUsersJsonNode.size() > 0) { JsonNode userContentData = getUsersJsonNode; User newUser = createUserWithApiResponse(userContentData); + // todo send mail + sendMail(newUser, generatePassword); return new ResponseEntity<>(newUser, HttpStatus.OK); } return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); @@ -287,6 +298,22 @@ public class IntegrationServiceImpl implements IntegrationService { } } + private void sendMail(User newUser, String generatePassword) { + try { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("Dear ").append(newUser.getFirstName()).append(", We are writing to inform you that your account has been created by the administrator. Please use following email and Password to login. \\n Email:") + .append(newUser.getEmail()).append(" Password: ").append(generatePassword).append(" Kindly do not share the credentials with anyone. Regards UPSMF Team"); + SimpleMailMessage message = new SimpleMailMessage(); + message.setText(stringBuilder.toString()); + message.setSubject("Account Login Credentials"); + message.setTo(newUser.getEmail()); + message.setFrom("upsmf.otp@upsmfac.org"); + javaMailSender.send(message); + } catch (Exception e) { + log.info("Error in send email"); + } + } + private String validateAndCreateDefaultPassword(CreateUserDto user) { if (user != null) { if (user.getCredentials() != null && !user.getCredentials().isEmpty()) { diff --git a/src/main/java/com/tarento/upsmf/examsAndAdmissions/util/Constants.java b/src/main/java/com/tarento/upsmf/examsAndAdmissions/util/Constants.java index 3790d6fbcb5a84a01b51468933496e4da1f29a58..2db5e4f3aa063e4f320c479640e8833ea4fc23e1 100644 --- a/src/main/java/com/tarento/upsmf/examsAndAdmissions/util/Constants.java +++ b/src/main/java/com/tarento/upsmf/examsAndAdmissions/util/Constants.java @@ -171,6 +171,7 @@ public class Constants { public static final String API_UPLOAD_DISPATCH_DETAILS = "api.upload.dispatchDetails"; public static final String API_HALLTICKET_GET = "api.hallticket.get"; + public static final String API_HALLTICKET_GET_BY_ID = "api.hallticket.get.id"; public static final String API_HALLTICKET_REQUEST_DATA_CORRECTION = "api.hallticket.requestDataCorrection"; public static final String API_HALLTICKET_GET_ALL_DATA_CORRECTION_REQUESTS = "api.hallticket.getAllDataCorrectionRequests"; public static final String API_HALLTICKET_APPROVE_DATA_CORRECTION = "api.hallticket.approveDataCorrection"; diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 32528d9ca602e525379db9b8fb6bc26cc16fbc9c..e2dab2583b0bfb2612384da7902cca51d2324745 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,14 +1,13 @@ server.port = 8083 -spring.datasource.url=jdbc:postgresql://localhost:5432/frac_tool +spring.datasource.url=jdbc:postgresql://localhost:5431/frac_tool spring.datasource.username=postgres -spring.datasource.password=postgres +spring.datasource.password=yoursupersecret spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect spring.jpa.properties.hibernate.format_sql=true spring.jpa.show-sql=false spring.jpa.hibernate.ddl-auto=update - #Storage Service properties storage.key={{storageKey}} container.name={{containerName}} @@ -21,7 +20,7 @@ entity.audit.index=entity-audit send-notification=false notification-url=https://igot-dev.in/api/notification/v1/notification/send/sync -auth-api-key=bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJYUkZWVDBidDlBNGdsWm5uSUF5d1BJYWFzdjRReGFHWSJ9.APB-Ma_1l_R5l0xRddDhhlYkxBxxwZzcQofyhoif2bE +auth-api-key= accesstoken.publickey.basepath=/home/radhesh/Desktop/FileStorage/keys sunbird_sso_url=https://registration.uphrh.in/auth/ sunbird_sso_realm=sunbird-rc @@ -92,15 +91,15 @@ api.user.details=http://localhost:5298/api/v1/user/details api.user.createUrl=http://localhost:5298/api/v1/user/create # gcp config -gcp.project.id=upsmf-368011 +gcp.project.id= gcp.bucket.name=dev-public-upsmf gcp.bucket.folder.name=exam gcp.max.file.size=2mb gcp.config.file.path= -gcp.client.id=113740098487205958998 -gcp.client.email=jenkins@upsmf-368011.iam.gserviceaccount.com -gcp.private.key.id=6aef3a75efe29225e6347244de3e8f1ddd8437df -gcp.pkcs.key=\n-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCqtqMByEGjddwE\n0oIkQRT4KukhPn65ozDQUfgop55VblUWeJEqmeGfTXdOTTVHpwwuYR9esrMgR5WN\n8IUGSLRmap9iyb4QBUV/gCjJIpsVu6HFMadBQCFceqzTqPMK6g6dwObNtDMxH6yP\nV47L/McwiPNoug2W+zBiRQ6YZ1GvQVY5s0KTX6EgkN/u3DW6kUu6NqcgqGuCWqUo\nEjss4HaX4D7DSbmKgOts/rKjwtDv9fgKLgbMlufwpxwWe/jygVUNvZumBARNIuVe\n+RbO6OvHb26H18KgkdDzB1VkzKX+750iIIa/KGrZHJStiw0zfri0/H0KdzbClvoO\nT6cBN/zVAgMBAAECggEAPN9dJsCKr0fSiaGqqFTQrmFWufT36SgIuu/PpmeGrP3n\nt1iMov02F8DevvwG+KLXVB5rui/MccE00eUm+gOo2DBC304CyOGoU3uWj4oYdNpw\nJ8m50ymT+87+m4bOC2FEjvn/EvCjpGuf84kMMS7UtDjRWtGlEOZG7XOkbbHBzdTQ\nGldzEgsqi2T8O5I31xZ1b2LJzAVODrv7TiVElhGcUB/1MkProjhkcyJx3B3cpClw\nY8Lq2R2urTf4NxMnmh/PmUfBzLQLauSDI/MH9NN57J1M/5uWYAIY/eaf8BtqEsbr\nXLmBP1WfNchXbfXLeadaiAX45ukt0y103qd0TmJa7QKBgQDdvgTcjKMddzfU6PeB\nXO3upl2FVLA6B89J/QiEKoeg4bkM2C3pNkGvgVA3HfHfauMhhwFee8mP14HLZQvb\n+0k9tL64CiznkuEfOBApkXJDsW0iAN3TwMj5zVRAVHWBRcexMt74CdySuKDOkV9G\n5feOXfdhOZM6z8LSfGs+2lYbQwKBgQDFFmj8Mtv4Pv5zsF1/UeFnuijkHO84dNYn\nflTB5Pmwb4Z5rhnJzG446cxr9f7E/+3yjd+xtBQf5ttPwvCBbZR20RO2jA5o/qij\nXaYHCjlE7yOpAfgU+p5K3JH9bTMLuPsSVaxBof7cFoqjFalVGmpR1qAj4UGHc9mT\nnV6CGCbqBwKBgQCTI+RV9XzHsLR7s5uJXAEGu56TOv81grkqf52HFjGpsB77Rvgw\nKLCtpUF1UYmOl37gYJWn/Lxjlr2qGgMkljqjl6x2s0nY4L5B2RHgg4MvKC0iwzBv\nsx2ppXaiuWi/v24jR35tWR3kvl72s8Bla3Q6JGBjQ7FO9U5yHd2Md5VrwQKBgAzy\nQOk4KgzvjmVpE2s2pLjcmK0LXYd23U5w1P57nQ9C9DFwB0+jNyZT7VK2MQsdyLKj\nMSuKKbxCvOtLYeMOoK8BYusd3iB1gfxhPXO+7y4hC1WhxHsUT2uZe5mLH8xIVW3J\n5OvWyVgJvwehd6MYfh1sHM7ekCBmsscokjm3fm7nAoGBAL5PXhD6rCaHGOo0KXEA\n0S6rzMI6qBzQvMyOVj7b0lwey6q+G2xl7Cc9IUmxVzhBe7daD6QSQ4dU91ZKaIys\nopfZWibHFcQm6I6FJI3ha73EOB2zyyl3xlBxK9fMQVN8gELdXhA8DBuMD+Qxj6Nr\nbqteFJLCyz7ATtETSb3+hP+G\n-----END PRIVATE KEY-----\n +gcp.client.id= +gcp.client.email= +gcp.private.key.id= +gcp.pkcs.key= gcp.sub.folder.path=exam #Redis @@ -114,4 +113,12 @@ user.roles=admin_superadmin,exams_admin,exams_institute,exams_student admin.allowed.endpoints=/payment institute.allowed.endpoints= student.allowed.endpoints= -user.management.exam.fee.auth.token= \ No newline at end of file +user.management.exam.fee.auth.token= + +# Mail +spring.mail.host=smtp.gmail.com +spring.mail.port=587 +spring.mail.username=upsmf.otp@upsmfac.org +spring.mail.password= +spring.mail.properties.mail.smtp.auth=true +spring.mail.properties.mail.smtp.starttls.enable=true diff --git a/upsmf-entity/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/ExamService.java b/upsmf-entity/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/ExamService.java deleted file mode 100644 index 29aae3827bff3933af7a654244e3bb922c8e3a0a..0000000000000000000000000000000000000000 --- a/upsmf-entity/src/main/java/com/tarento/upsmf/examsAndAdmissions/service/ExamService.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.tarento.upsmf.examsAndAdmissions.service; - -import com.tarento.upsmf.examsAndAdmissions.model.Exam; -import com.tarento.upsmf.examsAndAdmissions.repository.ExamRepository; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.util.List; - -@Service -@Slf4j -public class ExamService { - - @Autowired - private ExamRepository repository; - - public Exam createExam(Exam exam) { - log.info("Creating new Exam: {}", exam); - exam.setObsolete(0); - return repository.save(exam); - } - - public List<Exam> getAllExams() { - log.info("Fetching all active Exams..."); - return repository.findByObsolete(0); - } - - public Exam getExamById(Long id) { - log.info("Fetching Exam by ID: {}", id); - return repository.findByIdAndObsolete(id, 0).orElse(null); - } - - public Exam updateExam(Long id, Exam updatedExam) { - log.info("Updating Exam with ID: {}", id); - Exam existingExam = repository.findById(id).orElse(null); - if (existingExam != null) { - existingExam.setExamCycleId(updatedExam.getExamCycleId()); - existingExam.setExamDate(updatedExam.getExamDate()); - - // Update auditing metadata from the payload - existingExam.setModifiedBy(updatedExam.getModifiedBy()); - existingExam.setModifiedOn(updatedExam.getModifiedOn()); - - // Soft delete or status flag, if you want to allow it from the payload: - existingExam.setObsolete(updatedExam.getObsolete()); - - return repository.save(existingExam); - } - log.warn("Exam with ID: {} not found!", id); - return null; - } - - - - public void deleteExam(Long id) { - log.info("Soft-deleting Exam with ID: {}", id); - Exam exam = repository.findById(id).orElse(null); - if (exam != null) { - exam.setObsolete(1); - repository.save(exam); - } else { - log.warn("Exam with ID: {} not found for deletion!", id); - } - } - - public void restoreExam(Long id) { - log.info("Restoring soft-deleted Exam with ID: {}", id); - Exam exam = repository.findById(id).orElse(null); - if (exam != null && exam.getObsolete() == 1) { - exam.setObsolete(0); - repository.save(exam); - } else { - log.warn("Exam with ID: {} not found for restoration!", id); - } - } -} \ No newline at end of file