From a0cb4ae2eefb7afc3572b664f2f25d88d6aae046 Mon Sep 17 00:00:00 2001 From: elmer-20 <80175046+elmer-20@users.noreply.github.com> Date: Tue, 14 Apr 2026 13:44:18 -0500 Subject: [PATCH] service --- Dockerfile.dev | 2 +- .../controller/CalificacionController.java | 31 ++ .../controller/ExcelController.java | 17 +- .../controller/ExcelResultadoController.java | 20 +- .../controller/ResultadoController.java | 11 +- .../ingresantes/entity/ClaveExamen.java | 2 + .../ingresantes/entity/Postulante.java | 4 +- .../entity/ResultadoAsignatura.java | 44 ++ .../ingresantes/entity/ResultadoExamen.java | 12 +- .../repository/AsignaturaRepository.java | 9 +- .../repository/ClaveExamenRepository.java | 5 + .../ResultadoAsignaturaRepository.java | 10 + .../repository/ResultadoExamenRepository.java | 10 +- .../service/CalificacionCursoService.java | 128 +++++ .../service/ExcelResultadoService.java | 257 +++++---- .../ingresantes/service/ExcelService.java | 490 +++++++++++++----- .../ingresantes/service/ResultadoService.java | 6 +- 17 files changed, 803 insertions(+), 255 deletions(-) create mode 100644 src/main/java/com/service/ingresantes/controller/CalificacionController.java create mode 100644 src/main/java/com/service/ingresantes/entity/ResultadoAsignatura.java create mode 100644 src/main/java/com/service/ingresantes/repository/ResultadoAsignaturaRepository.java create mode 100644 src/main/java/com/service/ingresantes/service/CalificacionCursoService.java diff --git a/Dockerfile.dev b/Dockerfile.dev index 2c615ed..385eb0a 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -1,5 +1,5 @@ # Usa Maven y JDK para compilar y correr código -FROM maven:3.9.2-eclipse-temurin-17 +FROM eclipse-temurin:25-jdk WORKDIR /app diff --git a/src/main/java/com/service/ingresantes/controller/CalificacionController.java b/src/main/java/com/service/ingresantes/controller/CalificacionController.java new file mode 100644 index 0000000..6d37779 --- /dev/null +++ b/src/main/java/com/service/ingresantes/controller/CalificacionController.java @@ -0,0 +1,31 @@ +package com.service.ingresantes.controller; + +import com.service.ingresantes.service.CalificacionCursoService; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +@RestController +@RequestMapping("/api/calificacion") +public class CalificacionController { + + private final CalificacionCursoService calificacionCursoService; + + public CalificacionController(CalificacionCursoService calificacionCursoService) { + this.calificacionCursoService = calificacionCursoService; + } + + @PostMapping("/calificar/{procesoId}") + public Map calificarCursos(@PathVariable Long procesoId) { + + int registros = calificacionCursoService.calificarCursos(procesoId); + + Map response = new HashMap<>(); + response.put("mensaje", "Calificación por asignaturas completada"); + response.put("proceso", procesoId); + response.put("registros_generados", registros); + + return response; + } +} \ No newline at end of file diff --git a/src/main/java/com/service/ingresantes/controller/ExcelController.java b/src/main/java/com/service/ingresantes/controller/ExcelController.java index 65a7030..a9c19ec 100644 --- a/src/main/java/com/service/ingresantes/controller/ExcelController.java +++ b/src/main/java/com/service/ingresantes/controller/ExcelController.java @@ -7,6 +7,7 @@ import org.springframework.web.multipart.MultipartFile; @RestController @RequestMapping("/api/excel") +@CrossOrigin(origins = "*") public class ExcelController { private final ExcelService excelService; @@ -17,16 +18,24 @@ public class ExcelController { @PostMapping("/upload") public ResponseEntity uploadExcel(@RequestParam("file") MultipartFile file) { + try { - excelService.importarExcel(file); - return ResponseEntity.ok("Archivo subido y procesado correctamente!"); + if (file == null || file.isEmpty()) { + return ResponseEntity.badRequest().body("No se recibió ningún archivo."); + } + + + String resultado = excelService.importarExcel(file); + return ResponseEntity.ok(resultado); + } catch (Exception e) { + e.printStackTrace(); return ResponseEntity.badRequest().body("Error al procesar el archivo: " + e.getMessage()); } } @GetMapping("/ping") - public String ping() { - return "API funcionando123456!"; + public ResponseEntity ping() { + return ResponseEntity.ok("API funcionando correctamente"); } } \ No newline at end of file diff --git a/src/main/java/com/service/ingresantes/controller/ExcelResultadoController.java b/src/main/java/com/service/ingresantes/controller/ExcelResultadoController.java index 89ccf2e..454a8be 100644 --- a/src/main/java/com/service/ingresantes/controller/ExcelResultadoController.java +++ b/src/main/java/com/service/ingresantes/controller/ExcelResultadoController.java @@ -18,22 +18,28 @@ public class ExcelResultadoController { @PostMapping("/upload-resultados") public ResponseEntity uploadResultados( - @RequestParam("file") MultipartFile file) { + @RequestParam("file") MultipartFile file, + @RequestParam("dia") Integer dia) { if (file.isEmpty()) { return ResponseEntity.badRequest().body("El archivo está vacío"); } - try { + if (dia == null || dia < 1) { + return ResponseEntity.badRequest() + .body("El parámetro 'dia' es requerido y debe ser >= 1"); + } - excelResultadoService.importarExcelResultados(file); + try { + // 🔥 AQUÍ CAPTURAS EL RESUMEN + String resultado = excelResultadoService.importarExcelResultados(file, dia); - return ResponseEntity.ok("Archivo de resultados procesado correctamente"); + return ResponseEntity.ok( + "Archivo del día " + dia + " procesado correctamente\n\n" + resultado + ); } catch (Exception e) { - - return ResponseEntity - .badRequest() + return ResponseEntity.badRequest() .body("Error al procesar el archivo: " + e.getMessage()); } } diff --git a/src/main/java/com/service/ingresantes/controller/ResultadoController.java b/src/main/java/com/service/ingresantes/controller/ResultadoController.java index 94d5a2c..3aeb278 100644 --- a/src/main/java/com/service/ingresantes/controller/ResultadoController.java +++ b/src/main/java/com/service/ingresantes/controller/ResultadoController.java @@ -19,20 +19,21 @@ public class ResultadoController { this.resultadoService = resultadoService; } - // Buscar resultado por DNI y proceso - @GetMapping("/{dni}/{procesoId}") + // Buscar resultado por DNI, proceso y día + @GetMapping("/{dni}/{procesoId}/{dia}") public ResponseEntity obtenerResultado( @PathVariable String dni, - @PathVariable Long procesoId) { + @PathVariable Long procesoId, + @PathVariable Integer dia) { Optional resultado = - resultadoService.obtenerResultado(dni, procesoId); + resultadoService.obtenerResultado(dni, procesoId, dia); if (resultado.isEmpty()) { return ResponseEntity .badRequest() - .body("No se encontró resultado para ese DNI y proceso"); + .body("No se encontró resultado para ese DNI, proceso y día"); } return ResponseEntity.ok(resultado.get()); diff --git a/src/main/java/com/service/ingresantes/entity/ClaveExamen.java b/src/main/java/com/service/ingresantes/entity/ClaveExamen.java index 1c9176b..32aa957 100644 --- a/src/main/java/com/service/ingresantes/entity/ClaveExamen.java +++ b/src/main/java/com/service/ingresantes/entity/ClaveExamen.java @@ -30,4 +30,6 @@ public class ClaveExamen { @ManyToOne @JoinColumn(name = "area_id") private Area area; + + } \ No newline at end of file diff --git a/src/main/java/com/service/ingresantes/entity/Postulante.java b/src/main/java/com/service/ingresantes/entity/Postulante.java index f587f2b..925a4bf 100644 --- a/src/main/java/com/service/ingresantes/entity/Postulante.java +++ b/src/main/java/com/service/ingresantes/entity/Postulante.java @@ -53,4 +53,6 @@ public class Postulante { @Column(name = "distrito_colegio") private String distritoColegio; -} \ No newline at end of file +} + + diff --git a/src/main/java/com/service/ingresantes/entity/ResultadoAsignatura.java b/src/main/java/com/service/ingresantes/entity/ResultadoAsignatura.java new file mode 100644 index 0000000..c5cfaa2 --- /dev/null +++ b/src/main/java/com/service/ingresantes/entity/ResultadoAsignatura.java @@ -0,0 +1,44 @@ +package com.service.ingresantes.entity; + +import jakarta.persistence.*; +import lombok.*; + +@Entity +@Table(name = "resultado_asignatura") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ResultadoAsignatura { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + // resultado del examen + @ManyToOne + @JoinColumn(name = "resultado_examen_id", nullable = false) + private ResultadoExamen resultadoExamen; + + // proceso + @ManyToOne + @JoinColumn(name = "proceso_id", nullable = false) + private Proceso proceso; + + // área + @ManyToOne + @JoinColumn(name = "area_id", nullable = false) + private Area area; + + // curso + @ManyToOne + @JoinColumn(name = "asignatura_id", nullable = false) + private Asignatura asignatura; + + // estadísticas + private Integer correctas; + private Integer incorrectas; + private Integer blanco; + + private Double puntaje; +} \ No newline at end of file diff --git a/src/main/java/com/service/ingresantes/entity/ResultadoExamen.java b/src/main/java/com/service/ingresantes/entity/ResultadoExamen.java index b44477d..5304d4d 100644 --- a/src/main/java/com/service/ingresantes/entity/ResultadoExamen.java +++ b/src/main/java/com/service/ingresantes/entity/ResultadoExamen.java @@ -8,7 +8,7 @@ import lombok.Data; @Table( name = "resultado_examen", uniqueConstraints = { - @UniqueConstraint(columnNames = {"inscripcion_id"}) + @UniqueConstraint(columnNames = {"inscripcion_id", "dia"}) } ) public class ResultadoExamen { @@ -17,7 +17,7 @@ public class ResultadoExamen { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @OneToOne + @ManyToOne @JoinColumn(name = "inscripcion_id", nullable = false) private Inscripcion inscripcion; @@ -25,10 +25,16 @@ public class ResultadoExamen { @JoinColumn(name = "proceso_id", nullable = false) private Proceso proceso; + @Column(nullable = false) + private Integer dia; + private Double puntaje; + + @Column(name = "vocacional", nullable = true) + private Double vocacional; // ← NUEVO, puede ser null @Column(length = 2) - private String apto; // SI / NO / CL + private String apto; private String obs; diff --git a/src/main/java/com/service/ingresantes/repository/AsignaturaRepository.java b/src/main/java/com/service/ingresantes/repository/AsignaturaRepository.java index c921dd8..5ead789 100644 --- a/src/main/java/com/service/ingresantes/repository/AsignaturaRepository.java +++ b/src/main/java/com/service/ingresantes/repository/AsignaturaRepository.java @@ -2,10 +2,11 @@ package com.service.ingresantes.repository; import com.service.ingresantes.entity.Asignatura; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; -@Repository +import java.util.List; + public interface AsignaturaRepository extends JpaRepository { - // Aquí puedes agregar consultas personalizadas si lo necesitas - // Ejemplo: List findByNombre(String nombre); + + List findByAreaIdOrderByCodigo(Long areaId); + } \ No newline at end of file diff --git a/src/main/java/com/service/ingresantes/repository/ClaveExamenRepository.java b/src/main/java/com/service/ingresantes/repository/ClaveExamenRepository.java index c4d5b6d..63544c9 100644 --- a/src/main/java/com/service/ingresantes/repository/ClaveExamenRepository.java +++ b/src/main/java/com/service/ingresantes/repository/ClaveExamenRepository.java @@ -11,5 +11,10 @@ public interface ClaveExamenRepository extends JpaRepository // Busca una clave por proceso, área e idExamen Optional findByProcesoIdAndAreaIdAndIdExamen(Long procesoId, Long areaId, String idExamen); + Optional findByProcesoIdAndAreaIdAndTipo( + Long procesoId, + Long areaId, + String tipo + ); } \ No newline at end of file diff --git a/src/main/java/com/service/ingresantes/repository/ResultadoAsignaturaRepository.java b/src/main/java/com/service/ingresantes/repository/ResultadoAsignaturaRepository.java new file mode 100644 index 0000000..9253632 --- /dev/null +++ b/src/main/java/com/service/ingresantes/repository/ResultadoAsignaturaRepository.java @@ -0,0 +1,10 @@ +package com.service.ingresantes.repository; + +import com.service.ingresantes.entity.ResultadoAsignatura; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ResultadoAsignaturaRepository extends JpaRepository { + + boolean existsByProcesoId(Long procesoId); + +} \ No newline at end of file diff --git a/src/main/java/com/service/ingresantes/repository/ResultadoExamenRepository.java b/src/main/java/com/service/ingresantes/repository/ResultadoExamenRepository.java index e4c5d79..05a0ace 100644 --- a/src/main/java/com/service/ingresantes/repository/ResultadoExamenRepository.java +++ b/src/main/java/com/service/ingresantes/repository/ResultadoExamenRepository.java @@ -9,20 +9,18 @@ import java.util.Optional; public interface ResultadoExamenRepository extends JpaRepository { - boolean existsByInscripcionId(Long inscripcionId); + boolean existsByInscripcionIdAndDia(Long inscripcionId, Integer dia); - // Buscar resultado por DNI y proceso @Query(""" SELECT r FROM ResultadoExamen r JOIN r.inscripcion i JOIN i.postulante p WHERE p.dni = :dni AND i.proceso.id = :procesoId + AND r.dia = :dia """) - Optional findByDniAndProceso(String dni, Long procesoId); + Optional findByDniAndProcesoAndDia(String dni, Long procesoId, Integer dia); - - // Ranking por proceso @Query(""" SELECT r FROM ResultadoExamen r JOIN r.inscripcion i @@ -30,4 +28,6 @@ public interface ResultadoExamenRepository extends JpaRepository findRankingByProceso(Long procesoId); + + List findByProcesoId(Long procesoId); } \ No newline at end of file diff --git a/src/main/java/com/service/ingresantes/service/CalificacionCursoService.java b/src/main/java/com/service/ingresantes/service/CalificacionCursoService.java new file mode 100644 index 0000000..340c501 --- /dev/null +++ b/src/main/java/com/service/ingresantes/service/CalificacionCursoService.java @@ -0,0 +1,128 @@ +package com.service.ingresantes.service; + +import com.service.ingresantes.entity.*; +import com.service.ingresantes.repository.*; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; + +@Service +@Transactional +public class CalificacionCursoService { + + private final ResultadoExamenRepository resultadoRepo; + private final ClaveExamenRepository claveRepo; + private final AsignaturaRepository asignaturaRepo; + private final ResultadoAsignaturaRepository resultadoAsignaturaRepo; + + public CalificacionCursoService( + ResultadoExamenRepository resultadoRepo, + ClaveExamenRepository claveRepo, + AsignaturaRepository asignaturaRepo, + ResultadoAsignaturaRepository resultadoAsignaturaRepo) { + + this.resultadoRepo = resultadoRepo; + this.claveRepo = claveRepo; + this.asignaturaRepo = asignaturaRepo; + this.resultadoAsignaturaRepo = resultadoAsignaturaRepo; + } + + public int calificarCursos(Long procesoId) { + + + if (resultadoAsignaturaRepo.existsByProcesoId(procesoId)) { + throw new RuntimeException("Este proceso ya fue calificado por cursos"); + } + + List resultados = resultadoRepo.findByProcesoId(procesoId); + + List listaGuardar = new ArrayList<>(); + + for (ResultadoExamen resultado : resultados) { + + String respuestas = resultado.getRespuestas(); + + if (respuestas == null || respuestas.isEmpty()) + continue; + + Long areaId = Long.parseLong(resultado.getIdExamen()); + String tipo = resultado.getTipo(); + + Optional claveOpt = + claveRepo.findByProcesoIdAndAreaIdAndTipo( + procesoId, + areaId, + tipo + ); + + if (claveOpt.isEmpty()) + continue; + + String clave = claveOpt.get().getClave(); + + List asignaturas = + asignaturaRepo.findByAreaIdOrderByCodigo(areaId); + + int pos = 0; + + for (Asignatura asignatura : asignaturas) { + + int preguntas = asignatura.getCantidadPreguntas(); + int fin = pos + preguntas; + + if (fin > respuestas.length()) + break; + + String resp = respuestas.substring(pos, fin); + String cla = clave.substring(pos, fin); + + int correctas = 0; + int incorrectas = 0; + int blanco = 0; + + for (int i = 0; i < resp.length(); i++) { + + char r = resp.charAt(i); + char c = cla.charAt(i); + + if (r == ' ' || r == '0') { + blanco++; + } + else if (r == c) { + correctas++; + } + else { + incorrectas++; + } + } + + double ponderacion = asignatura.getPonderacion(); + + double puntaje = + (correctas * 10 * ponderacion) + + (blanco * 2 * ponderacion); + + ResultadoAsignatura resultadoAsignatura = ResultadoAsignatura.builder() + .resultadoExamen(resultado) + .proceso(resultado.getProceso()) + .area(asignatura.getArea()) + .asignatura(asignatura) + .correctas(correctas) + .incorrectas(incorrectas) + .blanco(blanco) + .puntaje(puntaje) + .build(); + + listaGuardar.add(resultadoAsignatura); + + pos = fin; + } + } + + resultadoAsignaturaRepo.saveAll(listaGuardar); + + return listaGuardar.size(); + } +} \ No newline at end of file diff --git a/src/main/java/com/service/ingresantes/service/ExcelResultadoService.java b/src/main/java/com/service/ingresantes/service/ExcelResultadoService.java index d58548c..ae6c952 100644 --- a/src/main/java/com/service/ingresantes/service/ExcelResultadoService.java +++ b/src/main/java/com/service/ingresantes/service/ExcelResultadoService.java @@ -10,8 +10,9 @@ import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import jakarta.transaction.Transactional; + import java.io.InputStream; -import java.util.Optional; +import java.util.*; @Service public class ExcelResultadoService { @@ -22,141 +23,201 @@ public class ExcelResultadoService { public ExcelResultadoService( InscripcionRepository inscripcionRepo, ResultadoExamenRepository resultadoRepo) { - this.inscripcionRepo = inscripcionRepo; this.resultadoRepo = resultadoRepo; } private String getCellString(Cell cell) { - if (cell == null) return ""; - switch (cell.getCellType()) { - case STRING: return cell.getStringCellValue().trim(); - case NUMERIC: return String.valueOf((long) cell.getNumericCellValue()); - default: return ""; } } private Double getCellDouble(Cell cell) { - if (cell == null) return null; - - if (cell.getCellType() == CellType.NUMERIC) { - return cell.getNumericCellValue(); - } - + if (cell.getCellType() == CellType.NUMERIC) return cell.getNumericCellValue(); if (cell.getCellType() == CellType.STRING) { - return Double.parseDouble(cell.getStringCellValue()); + try { + return Double.parseDouble(cell.getStringCellValue()); + } catch (Exception e) { + return null; + } } - return null; } private Integer getCellInteger(Cell cell) { - if (cell == null) return null; - - if (cell.getCellType() == CellType.NUMERIC) { - return (int) cell.getNumericCellValue(); - } - + if (cell.getCellType() == CellType.NUMERIC) return (int) cell.getNumericCellValue(); if (cell.getCellType() == CellType.STRING) { - return Integer.parseInt(cell.getStringCellValue()); + try { + return Integer.parseInt(cell.getStringCellValue()); + } catch (Exception e) { + return null; + } } - return null; } - @Transactional - public void importarExcelResultados(MultipartFile file) throws Exception { - - InputStream is = file.getInputStream(); - Workbook workbook = WorkbookFactory.create(is); - Sheet sheet = workbook.getSheetAt(0); - - for (Row row : sheet) { - - if (row.getRowNum() == 0) continue; - - try { - - String dni = getCellString(row.getCell(0)); - String procesoStr = getCellString(row.getCell(1)); - - if (dni.isEmpty() || procesoStr.isEmpty()) { - continue; - } - - Long procesoId = Long.parseLong(procesoStr); - - Optional inscripcionOpt = - inscripcionRepo.findByPostulanteDniAndProcesoId(dni, procesoId); - - if (inscripcionOpt.isEmpty()) { - - System.out.println("No existe inscripción -> DNI " + dni); - continue; - } - - Inscripcion inscripcion = inscripcionOpt.get(); - - if (resultadoRepo.existsByInscripcionId(inscripcion.getId())) { + private void incrementar(Map mapa, String clave) { + mapa.put(clave, mapa.getOrDefault(clave, 0) + 1); + } - System.out.println("Resultado ya existe -> DNI " + dni); - continue; + @Transactional + public String importarExcelResultados(MultipartFile file, Integer dia) throws Exception { + + int totalFilas = 0; + int guardados = 0; + int omitidos = 0; + int errores = 0; + + int dniVacio = 0; + int procesoVacio = 0; + int inscripcionNoExiste = 0; + int duplicado = 0; + + Map omitidasPorCausa = new TreeMap<>(); + + // 🔥 NUEVO: lista de detalles de omitidos + List detalleOmitidos = new ArrayList<>(); + + try (InputStream is = file.getInputStream(); + Workbook workbook = WorkbookFactory.create(is)) { + + Sheet sheet = workbook.getSheetAt(0); + + for (Row row : sheet) { + + if (row.getRowNum() == 0) continue; + + totalFilas++; + + try { + + String dni = getCellString(row.getCell(0)); + String procesoStr = getCellString(row.getCell(1)); + + if (dni.isEmpty()) { + omitidos++; + dniVacio++; + detalleOmitidos.add("Fila " + (row.getRowNum()+1) + " -> DNI vacío"); + incrementar(omitidasPorCausa, "DNI vacío"); + continue; + } + + if (procesoStr.isEmpty()) { + omitidos++; + procesoVacio++; + detalleOmitidos.add("DNI: " + dni + " -> Proceso vacío"); + incrementar(omitidasPorCausa, "Proceso vacío"); + continue; + } + + Long procesoId; + try { + procesoId = Long.parseLong(procesoStr); + } catch (Exception e) { + omitidos++; + procesoVacio++; + detalleOmitidos.add("DNI: " + dni + " -> Proceso inválido: " + procesoStr); + incrementar(omitidasPorCausa, "Proceso inválido"); + continue; + } + + Optional inscripcionOpt = + inscripcionRepo.findByPostulanteDniAndProcesoId(dni, procesoId); + + if (inscripcionOpt.isEmpty()) { + omitidos++; + inscripcionNoExiste++; + detalleOmitidos.add("DNI: " + dni + " | Proceso: " + procesoId + " -> NO EXISTE INSCRIPCIÓN"); + incrementar(omitidasPorCausa, "Inscripción no existe"); + continue; + } + + Inscripcion inscripcion = inscripcionOpt.get(); + + if (resultadoRepo.existsByInscripcionIdAndDia(inscripcion.getId(), dia)) { + omitidos++; + duplicado++; + detalleOmitidos.add("DNI: " + dni + " | Proceso: " + procesoId + " -> DUPLICADO"); + incrementar(omitidasPorCausa, "Resultado duplicado"); + continue; + } + + Double puntaje = getCellDouble(row.getCell(2)); + Double vocacional = getCellDouble(row.getCell(3)); + String apto = getCellString(row.getCell(4)); + String obs = getCellString(row.getCell(5)); + String idExamen = getCellString(row.getCell(6)); + String litho = getCellString(row.getCell(7)); + String numLectura = getCellString(row.getCell(8)); + String tipo = getCellString(row.getCell(9)); + String calificar = getCellString(row.getCell(10)); + String aula = getCellString(row.getCell(11)); + String respuestas = getCellString(row.getCell(12)); + Integer puesto = getCellInteger(row.getCell(13)); + + ResultadoExamen resultado = new ResultadoExamen(); + resultado.setInscripcion(inscripcion); + resultado.setProceso(inscripcion.getProceso()); + resultado.setDia(dia); + resultado.setPuntaje(puntaje); + resultado.setVocacional(vocacional); + resultado.setApto(apto); + resultado.setObs(obs); + resultado.setIdExamen(idExamen); + resultado.setLitho(litho); + resultado.setNumLectura(numLectura); + resultado.setTipo(tipo); + resultado.setCalificar(calificar); + resultado.setAula(aula); + resultado.setRespuestas(respuestas); + resultado.setPuesto(puesto); + + resultadoRepo.save(resultado); + guardados++; + + } catch (Exception e) { + errores++; + detalleOmitidos.add("Fila " + (row.getRowNum()+1) + " -> ERROR: " + e.getMessage()); + incrementar(omitidasPorCausa, "Error interno"); } + } + } - Double puntaje = getCellDouble(row.getCell(2)); - String apto = getCellString(row.getCell(3)); - String obs = getCellString(row.getCell(4)); - - String idExamen = getCellString(row.getCell(5)); - String litho = getCellString(row.getCell(6)); - String numLectura = getCellString(row.getCell(7)); - String tipo = getCellString(row.getCell(8)); - String calificar = getCellString(row.getCell(9)); - String aula = getCellString(row.getCell(10)); - String respuestas = getCellString(row.getCell(11)); - - Integer puesto = getCellInteger(row.getCell(12)); - - ResultadoExamen resultado = new ResultadoExamen(); - - resultado.setInscripcion(inscripcion); - resultado.setProceso(inscripcion.getProceso()); - - resultado.setPuntaje(puntaje); - resultado.setApto(apto); - resultado.setObs(obs); - - resultado.setIdExamen(idExamen); - resultado.setLitho(litho); - resultado.setNumLectura(numLectura); - resultado.setTipo(tipo); - resultado.setCalificar(calificar); - resultado.setAula(aula); - resultado.setRespuestas(respuestas); - - resultado.setPuesto(puesto); + StringBuilder sb = new StringBuilder(); - resultadoRepo.save(resultado); + sb.append("IMPORTACIÓN RESULTADOS\n"); + sb.append("Total filas: ").append(totalFilas).append("\n"); + sb.append("Guardados: ").append(guardados).append("\n"); + sb.append("Omitidos: ").append(omitidos).append("\n"); + sb.append("Errores: ").append(errores).append("\n\n"); - System.out.println("Resultado guardado -> DNI " + dni); + sb.append("DETALLE:\n"); + sb.append("- DNI vacío: ").append(dniVacio).append("\n"); + sb.append("- Proceso vacío/inválido: ").append(procesoVacio).append("\n"); + sb.append("- Inscripción no existe: ").append(inscripcionNoExiste).append("\n"); + sb.append("- Resultado duplicado: ").append(duplicado).append("\n\n"); - } catch (Exception e) { + sb.append("CAUSAS AGRUPADAS:\n"); + for (Map.Entry entry : omitidasPorCausa.entrySet()) { + sb.append("- ").append(entry.getKey()).append(": ") + .append(entry.getValue()).append("\n"); + } - System.out.println("Error fila " + row.getRowNum() + " -> " + e.getMessage()); - } + // 🔥 NUEVO BLOQUE + sb.append("\nDETALLE DE DNIs OMITIDOS:\n"); + for (String d : detalleOmitidos) { + sb.append("- ").append(d).append("\n"); } - workbook.close(); - is.close(); + return sb.toString(); } } \ No newline at end of file diff --git a/src/main/java/com/service/ingresantes/service/ExcelService.java b/src/main/java/com/service/ingresantes/service/ExcelService.java index dcfcc7d..2c9472d 100644 --- a/src/main/java/com/service/ingresantes/service/ExcelService.java +++ b/src/main/java/com/service/ingresantes/service/ExcelService.java @@ -1,17 +1,28 @@ package com.service.ingresantes.service; -import com.service.ingresantes.entity.*; -import com.service.ingresantes.repository.*; +import com.service.ingresantes.entity.Inscripcion; +import com.service.ingresantes.entity.Modalidad; +import com.service.ingresantes.entity.Postulante; +import com.service.ingresantes.entity.Proceso; +import com.service.ingresantes.entity.ProgramaEstudio; +import com.service.ingresantes.repository.InscripcionRepository; +import com.service.ingresantes.repository.ModalidadRepository; +import com.service.ingresantes.repository.PostulanteRepository; +import com.service.ingresantes.repository.ProcesoRepository; +import com.service.ingresantes.repository.ProgramaRepository; +import jakarta.transaction.Transactional; import org.apache.poi.ss.usermodel.*; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; -import jakarta.transaction.Transactional; import java.io.InputStream; import java.time.LocalDate; import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; +import java.time.ZoneId; +import java.util.Map; + import java.util.Optional; +import java.util.TreeMap; @Service public class ExcelService { @@ -34,157 +45,388 @@ public class ExcelService { this.inscripcionRepo = inscripcionRepo; } - // --- Método auxiliar para leer cualquier celda como String --- private String getCellStringValue(Cell cell) { if (cell == null) return ""; - switch (cell.getCellType()) { - case STRING: - return cell.getStringCellValue().trim(); - case NUMERIC: - if (DateUtil.isCellDateFormatted(cell)) { - return cell.getLocalDateTimeCellValue().toLocalDate().toString(); - } else { - return String.valueOf((long) cell.getNumericCellValue()); + + try { + return switch (cell.getCellType()) { + case STRING -> cell.getStringCellValue().trim(); + + case NUMERIC -> { + if (DateUtil.isCellDateFormatted(cell)) { + yield cell.getLocalDateTimeCellValue().toLocalDate().toString(); + } else { + double value = cell.getNumericCellValue(); + long longValue = (long) value; + if (value == longValue) { + yield String.valueOf(longValue); + } else { + yield String.valueOf(value); + } + } + } + + case BOOLEAN -> String.valueOf(cell.getBooleanCellValue()); + + case FORMULA -> { + try { + FormulaEvaluator evaluator = cell.getSheet() + .getWorkbook() + .getCreationHelper() + .createFormulaEvaluator(); + + CellValue cellValue = evaluator.evaluate(cell); + + yield switch (cellValue.getCellType()) { + case STRING -> cellValue.getStringValue().trim(); + case NUMERIC -> { + double value = cellValue.getNumberValue(); + long longValue = (long) value; + if (value == longValue) { + yield String.valueOf(longValue); + } else { + yield String.valueOf(value); + } + } + case BOOLEAN -> String.valueOf(cellValue.getBooleanValue()); + default -> ""; + }; + } catch (Exception e) { + yield ""; + } } - case BOOLEAN: - return String.valueOf(cell.getBooleanCellValue()); - case FORMULA: - return cell.getCellFormula(); - default: - return ""; + + case BLANK -> ""; + default -> ""; + }; + } catch (Exception e) { + return ""; } } - @Transactional - public void importarExcel(MultipartFile file) throws Exception { - InputStream is = file.getInputStream(); - Workbook workbook = WorkbookFactory.create(is); - Sheet sheet = workbook.getSheetAt(0); + private LocalDate getCellLocalDate(Cell cell) { + if (cell == null) return null; - DateTimeFormatter fechaHoraFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + try { + if (cell.getCellType() == CellType.NUMERIC && DateUtil.isCellDateFormatted(cell)) { + return cell.getDateCellValue() + .toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + } - for (Row row : sheet) { - if (row.getRowNum() == 0) continue; // Saltar encabezado + String value = getCellStringValue(cell); + if (value == null || value.isBlank()) return null; - String dni = getCellStringValue(row.getCell(0)); - if (dni.isEmpty()) { - System.out.println("Fila " + row.getRowNum() + ": DNI vacío, se omite"); - continue; + return LocalDate.parse(value.trim()); + } catch (Exception e) { + return null; + } + } + + private LocalDateTime getCellLocalDateTime(Cell cell) { + if (cell == null) return null; + + try { + if (cell.getCellType() == CellType.NUMERIC && DateUtil.isCellDateFormatted(cell)) { + return cell.getDateCellValue() + .toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDateTime(); } - Postulante postulante = postulanteRepo.findById(dni).orElseGet(() -> { + String value = getCellStringValue(cell); + if (value == null || value.isBlank()) return null; + + try { + return LocalDateTime.parse(value.trim().replace(" ", "T")); + } catch (Exception e) { + try { + return LocalDate.parse(value.trim()).atStartOfDay(); + } catch (Exception ex) { + return null; + } + } + } catch (Exception e) { + return null; + } + } + + private Integer parseInteger(String value) { + try { + if (value == null || value.isBlank()) return null; + return Integer.parseInt(value.trim()); + } catch (Exception e) { + return null; + } + } + + private Long parseLong(String value) { + try { + if (value == null || value.isBlank()) return null; + return Long.parseLong(value.trim()); + } catch (Exception e) { + return null; + } + } + + private void incrementar(Map mapa, String clave) { + mapa.put(clave, mapa.getOrDefault(clave, 0) + 1); + } + + @Transactional + public String importarExcel(MultipartFile file) throws Exception { + int totalFilas = 0; + int postulantesCreados = 0; + int inscripcionesGuardadas = 0; + int filasOmitidas = 0; + int errores = 0; + + int dniVacio = 0; + int procesoVacio = 0; + int procesoInvalido = 0; + int procesoNoEncontrado = 0; + int programaInvalido = 0; + int programaNoEncontrado = 0; + int modalidadInvalida = 0; + int modalidadNoEncontrada = 0; + int inscripcionDuplicada = 0; + + Map omitidasPorProceso = new TreeMap<>(); + Map omitidasPorPrograma = new TreeMap<>(); + Map omitidasPorModalidad = new TreeMap<>(); + Map omitidasPorProcesoModalidad = new TreeMap<>(); + Map omitidasPorCausa = new TreeMap<>(); + + try (InputStream is = file.getInputStream(); + Workbook workbook = WorkbookFactory.create(is)) { + + Sheet sheet = workbook.getSheetAt(0); + + for (Row row : sheet) { + if (row.getRowNum() == 0) continue; + totalFilas++; + + String dni = getCellStringValue(row.getCell(0)); + String procesoStr = getCellStringValue(row.getCell(18)); + String programaStr = getCellStringValue(row.getCell(19)); + String modalidadStr = getCellStringValue(row.getCell(20)); + + String procesoKey = procesoStr.isBlank() ? "SIN_PROCESO" : "Proceso " + procesoStr; + String programaKey = programaStr.isBlank() ? "SIN_PROGRAMA" : "Programa " + programaStr; + String modalidadKey = modalidadStr.isBlank() ? "SIN_MODALIDAD" : "Modalidad " + modalidadStr; + String procesoModalidadKey = procesoKey + " | " + modalidadKey; + try { - Postulante p = new Postulante(); - p.setDni(dni); - p.setPaterno(getCellStringValue(row.getCell(1))); - p.setMaterno(getCellStringValue(row.getCell(2))); - p.setNombres(getCellStringValue(row.getCell(3))); - p.setSexo(getCellStringValue(row.getCell(4))); - - String fechaNacStr = getCellStringValue(row.getCell(5)); - if (!fechaNacStr.isEmpty()) { - try { p.setFechaNacimiento(LocalDate.parse(fechaNacStr)); } catch (Exception e) {} + if (dni.isBlank()) { + filasOmitidas++; + dniVacio++; + incrementar(omitidasPorProceso, procesoKey); + incrementar(omitidasPorPrograma, programaKey); + incrementar(omitidasPorModalidad, modalidadKey); + incrementar(omitidasPorProcesoModalidad, procesoModalidadKey); + incrementar(omitidasPorCausa, "DNI vacío"); + continue; + } + + Postulante postulante = postulanteRepo.findById(dni).orElse(null); + + if (postulante == null) { + postulante = new Postulante(); + postulante.setDni(dni); + postulante.setPaterno(getCellStringValue(row.getCell(1))); + postulante.setMaterno(getCellStringValue(row.getCell(2))); + postulante.setNombres(getCellStringValue(row.getCell(3))); + postulante.setSexo(getCellStringValue(row.getCell(4))); + + LocalDate fechaNacimiento = getCellLocalDate(row.getCell(5)); + if (fechaNacimiento != null) postulante.setFechaNacimiento(fechaNacimiento); + + Integer edad = parseInteger(getCellStringValue(row.getCell(6))); + if (edad != null) postulante.setEdad(edad); + + postulante.setUbigeoResidencia(getCellStringValue(row.getCell(7))); + postulante.setDepartamentoResidencia(getCellStringValue(row.getCell(8))); + postulante.setProvinciaResidencia(getCellStringValue(row.getCell(9))); + postulante.setDistritoResidencia(getCellStringValue(row.getCell(10))); + + Integer egreso = parseInteger(getCellStringValue(row.getCell(11))); + if (egreso != null) postulante.setEgreso(egreso); + + postulante.setCodModular(getCellStringValue(row.getCell(12))); + postulante.setUbigeoColegio(getCellStringValue(row.getCell(13))); + postulante.setDepartamentoColegio(getCellStringValue(row.getCell(14))); + postulante.setProvinciaColegio(getCellStringValue(row.getCell(15))); + postulante.setDistritoColegio(getCellStringValue(row.getCell(16))); + + postulante = postulanteRepo.save(postulante); + postulantesCreados++; } - String edadStr = getCellStringValue(row.getCell(6)); - if (!edadStr.isEmpty()) { - try { p.setEdad(Integer.parseInt(edadStr)); } catch (NumberFormatException ignored) {} + LocalDateTime fechaInscripcion = getCellLocalDateTime(row.getCell(17)); + if (fechaInscripcion == null) { + fechaInscripcion = LocalDateTime.now(); } - p.setUbigeoResidencia(getCellStringValue(row.getCell(7))); - p.setDepartamentoResidencia(getCellStringValue(row.getCell(8))); - p.setProvinciaResidencia(getCellStringValue(row.getCell(9))); - p.setDistritoResidencia(getCellStringValue(row.getCell(10))); + if (procesoStr.isBlank()) { + filasOmitidas++; + procesoVacio++; + incrementar(omitidasPorProceso, procesoKey); + incrementar(omitidasPorPrograma, programaKey); + incrementar(omitidasPorModalidad, modalidadKey); + incrementar(omitidasPorProcesoModalidad, procesoModalidadKey); + incrementar(omitidasPorCausa, "Proceso vacío"); + continue; + } - String egresoStr = getCellStringValue(row.getCell(11)); - if (!egresoStr.isEmpty()) { - try { p.setEgreso(Integer.parseInt(egresoStr)); } catch (NumberFormatException ignored) {} + Long procesoId = parseLong(procesoStr); + if (procesoId == null) { + filasOmitidas++; + procesoInvalido++; + incrementar(omitidasPorProceso, procesoKey); + incrementar(omitidasPorPrograma, programaKey); + incrementar(omitidasPorModalidad, modalidadKey); + incrementar(omitidasPorProcesoModalidad, procesoModalidadKey); + incrementar(omitidasPorCausa, "Proceso inválido"); + continue; } - p.setCodModular(getCellStringValue(row.getCell(12))); - p.setUbigeoColegio(getCellStringValue(row.getCell(13))); - p.setDepartamentoColegio(getCellStringValue(row.getCell(14))); - p.setProvinciaColegio(getCellStringValue(row.getCell(15))); - p.setDistritoColegio(getCellStringValue(row.getCell(16))); + Optional procesoOpt = procesoRepo.findById(procesoId); + if (procesoOpt.isEmpty()) { + filasOmitidas++; + procesoNoEncontrado++; + incrementar(omitidasPorProceso, procesoKey); + incrementar(omitidasPorPrograma, programaKey); + incrementar(omitidasPorModalidad, modalidadKey); + incrementar(omitidasPorProcesoModalidad, procesoModalidadKey); + incrementar(omitidasPorCausa, "Proceso no encontrado"); + continue; + } + Proceso proceso = procesoOpt.get(); - System.out.println("Fila " + row.getRowNum() + ": Postulante creado -> " + dni); - return postulanteRepo.save(p); - } catch (Exception e) { - System.out.println("Fila " + row.getRowNum() + ": Error guardando postulante " + dni + " -> " + e.getMessage()); - return null; - } - }); + Long programaId = parseLong(programaStr); + if (programaId == null) { + filasOmitidas++; + programaInvalido++; + incrementar(omitidasPorProceso, procesoKey); + incrementar(omitidasPorPrograma, programaKey); + incrementar(omitidasPorModalidad, modalidadKey); + incrementar(omitidasPorProcesoModalidad, procesoModalidadKey); + incrementar(omitidasPorCausa, "Programa inválido"); + continue; + } - if (postulante == null) continue; + Optional programaOpt = programaRepo.findById(programaId); + if (programaOpt.isEmpty()) { + filasOmitidas++; + programaNoEncontrado++; + incrementar(omitidasPorProceso, procesoKey); + incrementar(omitidasPorPrograma, programaKey); + incrementar(omitidasPorModalidad, modalidadKey); + incrementar(omitidasPorProcesoModalidad, procesoModalidadKey); + incrementar(omitidasPorCausa, "Programa no encontrado"); + continue; + } + ProgramaEstudio programa = programaOpt.get(); + + Long modalidadId = parseLong(modalidadStr); + if (modalidadId == null) { + filasOmitidas++; + modalidadInvalida++; + incrementar(omitidasPorProceso, procesoKey); + incrementar(omitidasPorPrograma, programaKey); + incrementar(omitidasPorModalidad, modalidadKey); + incrementar(omitidasPorProcesoModalidad, procesoModalidadKey); + incrementar(omitidasPorCausa, "Modalidad inválida"); + continue; + } + + Optional modalidadOpt = modalidadRepo.findById(modalidadId); + if (modalidadOpt.isEmpty()) { + filasOmitidas++; + modalidadNoEncontrada++; + incrementar(omitidasPorProceso, procesoKey); + incrementar(omitidasPorPrograma, programaKey); + incrementar(omitidasPorModalidad, modalidadKey); + incrementar(omitidasPorProcesoModalidad, procesoModalidadKey); + incrementar(omitidasPorCausa, "Modalidad no encontrada"); + continue; + } + Modalidad modalidad = modalidadOpt.get(); + + boolean existe = inscripcionRepo.existsByPostulanteAndProceso(postulante, proceso); + if (existe) { + filasOmitidas++; + inscripcionDuplicada++; + incrementar(omitidasPorProceso, procesoKey); + incrementar(omitidasPorPrograma, programaKey); + incrementar(omitidasPorModalidad, modalidadKey); + incrementar(omitidasPorProcesoModalidad, procesoModalidadKey); + incrementar(omitidasPorCausa, "Inscripción duplicada"); + continue; + } + + Inscripcion inscripcion = new Inscripcion(); + inscripcion.setFechaInscripcion(fechaInscripcion); + inscripcion.setPostulante(postulante); + inscripcion.setProceso(proceso); + inscripcion.setPrograma(programa); + inscripcion.setModalidad(modalidad); + inscripcionRepo.save(inscripcion); + inscripcionesGuardadas++; - String fechaInsStr = getCellStringValue(row.getCell(17)); - LocalDateTime fechaInscripcion; - if (!fechaInsStr.isEmpty()) { - try { - fechaInscripcion = LocalDateTime.parse(fechaInsStr, fechaHoraFormatter); } catch (Exception e) { - try { fechaInscripcion = LocalDate.parse(fechaInsStr).atStartOfDay(); } - catch (Exception ex) { fechaInscripcion = LocalDateTime.now(); } + errores++; + incrementar(omitidasPorCausa, "Error interno"); + System.out.println("Fila " + (row.getRowNum() + 1) + ": ERROR -> " + e.getMessage()); } - } else { - fechaInscripcion = LocalDateTime.now(); } + } - String procesoStr = getCellStringValue(row.getCell(18)); - if (procesoStr.isEmpty()) { - System.out.println("Fila " + row.getRowNum() + ": Proceso vacío, se omite"); - continue; - } - Long procesoId; - try { procesoId = Long.parseLong(procesoStr); } - catch (NumberFormatException e) { - System.out.println("Fila " + row.getRowNum() + ": Proceso inválido -> " + procesoStr); - continue; - } - Optional procesoOpt = procesoRepo.findById(procesoId); - if (procesoOpt.isEmpty()) { - System.out.println("Fila " + row.getRowNum() + ": Proceso no encontrado -> " + procesoId); - continue; - } - Proceso proceso = procesoOpt.get(); + StringBuilder sb = new StringBuilder(); + sb.append("Importación finalizada.\n"); + sb.append("Total filas: ").append(totalFilas).append("\n"); + sb.append("Postulantes creados: ").append(postulantesCreados).append("\n"); + sb.append("Inscripciones guardadas: ").append(inscripcionesGuardadas).append("\n"); + sb.append("Filas omitidas: ").append(filasOmitidas).append("\n"); + sb.append("Errores: ").append(errores).append("\n\n"); - String programaStr = getCellStringValue(row.getCell(19)); - Optional programaOpt = programaRepo.findById(Long.parseLong(programaStr)); - if (programaOpt.isEmpty()) { - System.out.println("Fila " + row.getRowNum() + ": Programa no encontrado -> " + programaStr); - continue; - } - ProgramaEstudio programa = programaOpt.get(); + sb.append("DETALLE POR CAUSA:\n"); + sb.append("- DNI vacío: ").append(dniVacio).append("\n"); + sb.append("- Proceso vacío: ").append(procesoVacio).append("\n"); + sb.append("- Proceso inválido: ").append(procesoInvalido).append("\n"); + sb.append("- Proceso no encontrado: ").append(procesoNoEncontrado).append("\n"); + sb.append("- Programa inválido: ").append(programaInvalido).append("\n"); + sb.append("- Programa no encontrado: ").append(programaNoEncontrado).append("\n"); + sb.append("- Modalidad inválida: ").append(modalidadInvalida).append("\n"); + sb.append("- Modalidad no encontrada: ").append(modalidadNoEncontrada).append("\n"); + sb.append("- Inscripción duplicada: ").append(inscripcionDuplicada).append("\n\n"); - String modalidadStr = getCellStringValue(row.getCell(20)); - Optional modalidadOpt = modalidadRepo.findById(Long.parseLong(modalidadStr)); - if (modalidadOpt.isEmpty()) { - System.out.println("Fila " + row.getRowNum() + ": Modalidad no encontrada -> " + modalidadStr); - continue; - } - Modalidad modalidad = modalidadOpt.get(); + sb.append("OMITIDAS POR PROCESO:\n"); + for (Map.Entry entry : omitidasPorProceso.entrySet()) { + sb.append("- ").append(entry.getKey()).append(": ").append(entry.getValue()).append("\n"); + } - boolean existe = inscripcionRepo.existsByPostulanteAndProceso(postulante, proceso); - if (existe) { - System.out.println("Fila " + row.getRowNum() + ": La inscripción ya existe para el postulante " + dni); - continue; - } + sb.append("\nOMITIDAS POR PROGRAMA:\n"); + for (Map.Entry entry : omitidasPorPrograma.entrySet()) { + sb.append("- ").append(entry.getKey()).append(": ").append(entry.getValue()).append("\n"); + } - try { - Inscripcion inscripcion = new Inscripcion(); - inscripcion.setFechaInscripcion(fechaInscripcion); - inscripcion.setPostulante(postulante); - inscripcion.setProceso(proceso); - inscripcion.setPrograma(programa); - inscripcion.setModalidad(modalidad); - inscripcionRepo.save(inscripcion); - System.out.println("Fila " + row.getRowNum() + ": Inscripción guardada -> " + dni); - } catch (Exception e) { - System.out.println("Fila " + row.getRowNum() + ": Error guardando inscripción -> " + e.getMessage()); - } + sb.append("\nOMITIDAS POR MODALIDAD:\n"); + for (Map.Entry entry : omitidasPorModalidad.entrySet()) { + sb.append("- ").append(entry.getKey()).append(": ").append(entry.getValue()).append("\n"); + } + + sb.append("\nOMITIDAS POR PROCESO Y MODALIDAD:\n"); + for (Map.Entry entry : omitidasPorProcesoModalidad.entrySet()) { + sb.append("- ").append(entry.getKey()).append(": ").append(entry.getValue()).append("\n"); + } + + sb.append("\nRESUMEN DE CAUSAS AGRUPADAS:\n"); + for (Map.Entry entry : omitidasPorCausa.entrySet()) { + sb.append("- ").append(entry.getKey()).append(": ").append(entry.getValue()).append("\n"); } - workbook.close(); - is.close(); + return sb.toString(); } } \ No newline at end of file diff --git a/src/main/java/com/service/ingresantes/service/ResultadoService.java b/src/main/java/com/service/ingresantes/service/ResultadoService.java index d127b53..3175ea0 100644 --- a/src/main/java/com/service/ingresantes/service/ResultadoService.java +++ b/src/main/java/com/service/ingresantes/service/ResultadoService.java @@ -16,10 +16,10 @@ public class ResultadoService { this.resultadoRepo = resultadoRepo; } - // Buscar resultado por DNI y proceso - public Optional obtenerResultado(String dni, Long procesoId) { + // Buscar resultado por DNI, proceso y día + public Optional obtenerResultado(String dni, Long procesoId, Integer dia) { - return resultadoRepo.findByDniAndProceso(dni, procesoId); + return resultadoRepo.findByDniAndProcesoAndDia(dni, procesoId, dia); } // Ranking por proceso