diff --git a/src/main/java/com/primefactorsolutions/model/Actividad.java b/src/main/java/com/primefactorsolutions/model/Actividad.java index d8d6f54..6b0a4b1 100644 --- a/src/main/java/com/primefactorsolutions/model/Actividad.java +++ b/src/main/java/com/primefactorsolutions/model/Actividad.java @@ -1,8 +1,5 @@ package com.primefactorsolutions.model; -import java.util.ArrayList; -import java.util.List; - public final class Actividad { private String nombre; private double lunes; @@ -12,11 +9,9 @@ public final class Actividad { private double viernes; private double sabado; private double domingo; - private String nombreActivEsp; + private String tarea; private double horas; - private static final List actividadesExistentes = new ArrayList<>(); - public Actividad(final Builder builder) { this.nombre = builder.nombre; this.lunes = builder.lunes; @@ -26,7 +21,7 @@ public final class Actividad { this.viernes = builder.viernes; this.sabado = builder.sabado; this.domingo = builder.domingo; - this.nombreActivEsp = builder.nombreActivEsp; // Cambié aquí también + this.tarea = builder.tarea; this.horas = builder.horas; } @@ -62,8 +57,8 @@ public final class Actividad { return domingo; } - public String getNombreActivEsp() { // Cambié aquí también - return nombreActivEsp; + public String getTarea() { // Cambié aquí también + return tarea; } public double getHoras() { @@ -80,17 +75,17 @@ public final class Actividad { private double viernes; private double sabado; private double domingo; - private String nombreActivEsp; // Cambié 'tarea' por 'descripcion' + private String tarea; // Cambié 'tarea' por 'descripcion' private double horas; - public Builder nombreActivEsp(final String nombreActivEsp, final double horas) { - this.nombreActivEsp = nombreActivEsp; + public Builder tarea(final String tarea, final double horas) { + this.tarea = tarea; this.horas = horas; return this; } - public Builder nombreActivEsp(final String nombreActivEsp) { - this.nombreActivEsp = nombreActivEsp; + public Builder tarea(final String tarea) { + this.tarea = tarea; return this; } diff --git a/src/main/java/com/primefactorsolutions/repositories/EmployeeRepository.java b/src/main/java/com/primefactorsolutions/repositories/EmployeeRepository.java index 3016f8e..3f09154 100644 --- a/src/main/java/com/primefactorsolutions/repositories/EmployeeRepository.java +++ b/src/main/java/com/primefactorsolutions/repositories/EmployeeRepository.java @@ -3,6 +3,7 @@ package com.primefactorsolutions.repositories; import com.primefactorsolutions.model.Employee; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.List; import java.util.Optional; import java.util.UUID; @@ -10,4 +11,7 @@ public interface EmployeeRepository extends JpaRepository { Optional findByUsername(String username); Optional findByPersonalEmail(String personalEmail); + Optional findByTeamIdAndLeadManagerTrue(UUID teamId); + + List findByTeamName(String teamName); } diff --git a/src/main/java/com/primefactorsolutions/service/EmployeeService.java b/src/main/java/com/primefactorsolutions/service/EmployeeService.java index e63c88a..646278a 100644 --- a/src/main/java/com/primefactorsolutions/service/EmployeeService.java +++ b/src/main/java/com/primefactorsolutions/service/EmployeeService.java @@ -48,6 +48,13 @@ public class EmployeeService { return null; } + public String getTeamLeadName(final UUID teamId) { + // Encuentra al empleado con el rol de lead_manager en el equipo especificado + Optional leadManager = employeeRepository.findByTeamIdAndLeadManagerTrue(teamId); + + return leadManager.map(employee -> employee.getFirstName() + " " + employee.getLastName()) + .orElse("No asignado"); + } public List findEmployees( final int start, final int pageSize, final String sortProperty, final boolean asc) { List employees = employeeRepository.findAll(); @@ -115,4 +122,10 @@ public class EmployeeService { public List findAllEmployees() { return employeeRepository.findAll(); } + + public List findEmployeesByTeam(final String teamName) { + return employeeRepository.findByTeamName(teamName); + } + + } \ No newline at end of file diff --git a/src/main/java/com/primefactorsolutions/service/HoursWorkedService.java b/src/main/java/com/primefactorsolutions/service/HoursWorkedService.java index d658b6f..2bfe882 100644 --- a/src/main/java/com/primefactorsolutions/service/HoursWorkedService.java +++ b/src/main/java/com/primefactorsolutions/service/HoursWorkedService.java @@ -32,7 +32,7 @@ public class HoursWorkedService { hoursWorkedRepository.deleteById(id); } - public List findByWeekNumber(int weekNumber) { + public List findByWeekNumber(final int weekNumber) { return hoursWorkedRepository.findByWeekNumber(weekNumber); } diff --git a/src/main/java/com/primefactorsolutions/service/ReportService.java b/src/main/java/com/primefactorsolutions/service/ReportService.java index beaa21a..15f6405 100644 --- a/src/main/java/com/primefactorsolutions/service/ReportService.java +++ b/src/main/java/com/primefactorsolutions/service/ReportService.java @@ -11,6 +11,7 @@ import lombok.SneakyThrows; import org.apache.pdfbox.io.MemoryUsageSetting; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.jetbrains.annotations.NotNull; import org.springframework.stereotype.Service; @@ -31,20 +32,59 @@ public class ReportService { // Este método ahora solo crea el archivo Excel a partir de los datos que recibe. public byte[] writeAsExcel(final String reportName, final List headers, - final List> data) + final List> data, final String selectedTeam, + final int weekNumber, final int currentYear) throws IOException { - return createExcelFile(reportName, headers, data); + return createExcelFile(reportName, headers, data, selectedTeam, weekNumber, currentYear); } private byte[] createExcelFile(final String reportName, final List headers, - final List> data) + final List> data, final String selectedTeam, + final int weekNumber, final int currentYear) throws IOException { try (Workbook workbook = new XSSFWorkbook(); ByteArrayOutputStream os = new ByteArrayOutputStream()) { Sheet sheet = workbook.createSheet(reportName); // Crear encabezados - Row headerRow = sheet.createRow(0); + // Crear una fila para el rótulo "Reporte por equipo" + Row titleRow = sheet.createRow(0); // Fila 0 para el rótulo + Cell titleCell = titleRow.createCell(0); + + // Concatenar el nombre del equipo al rótulo + String titleText = "Informe: " + weekNumber + "/" + currentYear; + titleCell.setCellValue(titleText); + + // Estilo del rótulo + CellStyle titleStyle = workbook.createCellStyle(); + Font titleFont = workbook.createFont(); + titleFont.setBold(true); + titleFont.setFontHeightInPoints((short) 14); // Tamaño de la fuente + titleStyle.setFont(titleFont); + titleCell.setCellStyle(titleStyle); + + // Fusionar celdas para el rótulo + sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, headers.size() - 1)); // Ajusta el rango de celdas + + // Crear filas adicionales con la información solicitada + Row asuntoRow = sheet.createRow(1); // Fila 1: Asunto + asuntoRow.createCell(0).setCellValue("Asunto: Informe semanal de horas trabajadas"); + sheet.addMergedRegion(new CellRangeAddress(1, 1, 0, headers.size() - 1)); + + Row semanaRow = sheet.createRow(2); // Fila 2: Semana + semanaRow.createCell(0).setCellValue("Semana: " + weekNumber); // Puedes insertar una fecha real aquí + sheet.addMergedRegion(new CellRangeAddress(2, 2, 0, headers.size() - 1)); + + Row horasCumplirRow = sheet.createRow(3); // Fila 3: Horas a cumplir + horasCumplirRow.createCell(0).setCellValue("Horas a cumplir: 40 horas"); // Puedes agregar las horas reales + sheet.addMergedRegion(new CellRangeAddress(3, 3, 0, headers.size() - 1)); + + Row teamLeadRow = sheet.createRow(4); // Fila 4: Team Lead + teamLeadRow.createCell(0).setCellValue("Team Lead: "); // Solo texto + sheet.addMergedRegion(new CellRangeAddress(4, 4, 0, headers.size() - 1)); + + // Crear encabezados (fila 5) + Row headerRow = sheet.createRow(5); // Los encabezados empiezan en la fila 5 CellStyle headerStyle = workbook.createCellStyle(); Font headerFont = workbook.createFont(); headerFont.setBold(true); @@ -56,20 +96,22 @@ public class ReportService { cell.setCellStyle(headerStyle); } - // Crear filas de datos + // Crear filas de datos (a partir de la fila 6) for (int i = 0; i < data.size(); i++) { - Row dataRow = sheet.createRow(i + 1); + Row dataRow = sheet.createRow(i + 6); // Los datos empiezan después de la fila de encabezados Map rowData = data.get(i); int cellIndex = 0; for (String key : headers) { Cell cell = dataRow.createCell(cellIndex++); Object value = rowData.get(key); - switch (value) { - case String s -> cell.setCellValue(s); - case Number number -> cell.setCellValue(number.doubleValue()); - case null -> cell.setCellValue(""); // Manejo de valores nulos - default -> { + if (value != null) { + if (value instanceof String) { + cell.setCellValue((String) value); + } else if (value instanceof Number) { + cell.setCellValue(((Number) value).doubleValue()); } + } else { + cell.setCellValue(""); // Manejo de valores nulos } } } diff --git a/src/main/java/com/primefactorsolutions/views/HoursWorkedView.java b/src/main/java/com/primefactorsolutions/views/HoursWorkedView.java index 94e94d3..7c1f644 100644 --- a/src/main/java/com/primefactorsolutions/views/HoursWorkedView.java +++ b/src/main/java/com/primefactorsolutions/views/HoursWorkedView.java @@ -17,8 +17,11 @@ import com.vaadin.flow.router.Route; import com.vaadin.flow.spring.annotation.SpringComponent; import jakarta.annotation.security.PermitAll; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Scope; import com.vaadin.flow.component.html.Label; +import org.springframework.web.servlet.HandlerMapping; +import org.springframework.web.servlet.view.InternalResourceViewResolver; import java.time.DayOfWeek; @@ -62,6 +65,11 @@ public class HoursWorkedView extends VerticalLayout { private final Label numeroSemanaLabel = new Label("Número de la Semana: "); private DatePicker fechaPicker = new DatePicker("Selecciona una fecha"); + @Autowired + private InternalResourceViewResolver defaultViewResolver; + @Qualifier("defaultServletHandlerMapping") + @Autowired + private HandlerMapping defaultServletHandlerMapping; public HoursWorkedView(final EmployeeService employeeService, final HoursWorkedService hoursWorkedService) { @@ -75,7 +83,8 @@ public class HoursWorkedView extends VerticalLayout { } private void configurarTareasEspecificas() { - tareasEspecificasDropdown.setItems("Entrevistas", "Reuniones", "Colaboraciones", "Aprendizajes", "Proyectos PFS", "Otros"); + tareasEspecificasDropdown.setItems("Entrevistas", "Reuniones", "Colaboraciones", + "Aprendizajes", "Proyectos PFS", "Otros"); tareasEspecificasDropdown.setPlaceholder("Selecciona una tarea..."); tareasEspecificasDropdown.addValueChangeListener(event -> { @@ -141,8 +150,18 @@ public class HoursWorkedView extends VerticalLayout { getUI().ifPresent(ui -> ui.navigate(HoursWorkedMonthView.class)); }); - equipoDropdown.setItems("Equipo 1", "Equipo 2", "Equipo 3"); + equipoDropdown.setItems("ABC", "DEF", "XYZ"); equipoDropdown.setWidth("250px"); + + equipoDropdown.addValueChangeListener(event -> { + String selectedEquipo = event.getValue(); + if (selectedEquipo != null) { + // Filtra la lista de empleados según el equipo seleccionado + List filteredEmployees = employeeService.findEmployeesByTeam(selectedEquipo); + employeeComboBox.setItems(filteredEmployees); + } + }); + setEmployeeComboBoxProperties(); HorizontalLayout filtersLayout = new HorizontalLayout(equipoDropdown, employeeComboBox); @@ -163,7 +182,8 @@ public class HoursWorkedView extends VerticalLayout { totalesLayout.setSpacing(true); totalesLayout.setPadding(true); - add(fechaPicker, fechasLabel, numeroSemanaLabel, filtersLayout, actividadFormLayout, tareasEspecificasLayout, grid,gridActividadesEspecificas, buttonsLayout, totalesLayout); + add(fechaPicker, fechasLabel, numeroSemanaLabel, filtersLayout, actividadFormLayout, + tareasEspecificasLayout, grid, gridActividadesEspecificas, buttonsLayout, totalesLayout); } private void configurarGrid() { @@ -183,7 +203,7 @@ public class HoursWorkedView extends VerticalLayout { private void configurarGridActividadesEspecificas() { gridActividadesEspecificas.removeAllColumns(); gridActividadesEspecificas.setItems(actividadesEspecificas); - gridActividadesEspecificas.addColumn(Actividad::getNombreActivEsp).setHeader("Actividad"); + gridActividadesEspecificas.addColumn(Actividad::getTarea).setHeader("Actividad"); gridActividadesEspecificas.addColumn(Actividad::getLunes).setHeader("Lunes"); gridActividadesEspecificas.addColumn(Actividad::getMartes).setHeader("Martes"); gridActividadesEspecificas.addColumn(Actividad::getMiercoles).setHeader("Miércoles"); @@ -191,7 +211,8 @@ public class HoursWorkedView extends VerticalLayout { gridActividadesEspecificas.addColumn(Actividad::getViernes).setHeader("Viernes"); gridActividadesEspecificas.addColumn(Actividad::getSabado).setHeader("Sábado"); gridActividadesEspecificas.addColumn(Actividad::getDomingo).setHeader("Domingo"); - gridActividadesEspecificas.addColumn(this::calcularTotalPorDia).setHeader("Total Día Específico").setKey("totalDiaEspecifico"); + gridActividadesEspecificas.addColumn(this::calcularTotalPorDia).setHeader("Total Día Específico") + .setKey("totalDiaEspecifico"); } private HorizontalLayout configurarFormularioActividades() { @@ -221,13 +242,14 @@ public class HoursWorkedView extends VerticalLayout { case FRIDAY -> actividadBuilder.viernes(horas); case SATURDAY -> actividadBuilder.sabado(horas); case SUNDAY -> actividadBuilder.domingo(horas); + default -> throw new IllegalArgumentException("Día seleccionado no válido: " + selectedDay); } String tareaSeleccionada = tareasEspecificasDropdown.getValue(); double horasTarea = parseHoras(horasTareaInput.getValue()); if (tareaSeleccionada != null && !tareaSeleccionada.isEmpty()) { - actividadBuilder.nombreActivEsp(tareaSeleccionada).lunes(horasTarea); + actividadBuilder.tarea(tareaSeleccionada).lunes(horasTarea); Actividad nuevaActividadEspecifica = actividadBuilder.build(); actividadesEspecificas.add(nuevaActividadEspecifica); gridActividadesEspecificas.setItems(actividadesEspecificas); @@ -255,7 +277,9 @@ public class HoursWorkedView extends VerticalLayout { Button agregarTareaButton = new Button("Agregar Tarea PFS", e -> { try { String tareaSeleccionada = tareasEspecificasDropdown.getValue(); - String tareaNombre = "Otros".equals(tareaSeleccionada) ? tareaEspecificaInput.getValue() : tareaSeleccionada; + String tareaNombre = "Otros" + .equals(tareaSeleccionada) ? tareaEspecificaInput + .getValue() : tareaSeleccionada; if (tareaNombre == null || tareaNombre.isEmpty()) { Notification.show("Por favor, especifica la tarea."); @@ -276,7 +300,7 @@ public class HoursWorkedView extends VerticalLayout { } DayOfWeek selectedDay = selectedDate.getDayOfWeek(); - Actividad.Builder actividadBuilder = new Actividad.Builder().nombreActivEsp(tareaNombre); + Actividad.Builder actividadBuilder = new Actividad.Builder().tarea(tareaNombre); switch (selectedDay) { case MONDAY -> actividadBuilder.lunes(horasTarea); @@ -286,6 +310,7 @@ public class HoursWorkedView extends VerticalLayout { case FRIDAY -> actividadBuilder.viernes(horasTarea); case SATURDAY -> actividadBuilder.sabado(horasTarea); case SUNDAY -> actividadBuilder.domingo(horasTarea); + default -> throw new IllegalArgumentException("Día seleccionado no válido: " + selectedDay); } Actividad nuevaActividadEspecifica = actividadBuilder.build(); @@ -307,7 +332,8 @@ public class HoursWorkedView extends VerticalLayout { } }); - HorizontalLayout layout= new HorizontalLayout(tareasEspecificasDropdown, tareaEspecificaInput, horasTareaInput, agregarTareaButton); + HorizontalLayout layout = new HorizontalLayout(tareasEspecificasDropdown, + tareaEspecificaInput, horasTareaInput, agregarTareaButton); layout.setSpacing(true); return layout; } @@ -354,7 +380,6 @@ public class HoursWorkedView extends VerticalLayout { Employee selectedEmployee = employeeComboBox.getValue(); String selectedEquipo = equipoDropdown.getValue(); - if (selectedEmployee == null || selectedEquipo == null) { Notification.show("Por favor selecciona un equipo y un empleado."); return; @@ -372,6 +397,7 @@ public class HoursWorkedView extends VerticalLayout { try { hoursWorkedService.saveHoursWorked(hoursWorked); // Usa saveHoursWorked directamente Notification.show("Actividades guardadas correctamente."); + System.out.println(hoursWorked); } catch (Exception e) { Notification.show("Error al guardar actividades: " + e.getMessage()); } diff --git a/src/main/java/com/primefactorsolutions/views/ReporteView.java b/src/main/java/com/primefactorsolutions/views/ReporteView.java index 030416c..1594cc5 100644 --- a/src/main/java/com/primefactorsolutions/views/ReporteView.java +++ b/src/main/java/com/primefactorsolutions/views/ReporteView.java @@ -1,13 +1,17 @@ package com.primefactorsolutions.views; import com.primefactorsolutions.model.HoursWorked; +import com.primefactorsolutions.model.Team; import com.primefactorsolutions.service.HoursWorkedService; import com.primefactorsolutions.service.ReportService; +import com.primefactorsolutions.service.TeamService; import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.combobox.ComboBox; -import com.vaadin.flow.component.datepicker.DatePicker; +import com.vaadin.flow.component.grid.Grid; import com.vaadin.flow.component.html.Anchor; import com.vaadin.flow.component.html.H2; +import com.vaadin.flow.component.html.Span; +import com.vaadin.flow.component.notification.Notification; import com.vaadin.flow.component.orderedlayout.HorizontalLayout; import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.router.PageTitle; @@ -15,10 +19,12 @@ import com.vaadin.flow.router.Route; import com.vaadin.flow.server.StreamResource; import jakarta.annotation.security.PermitAll; import org.springframework.beans.factory.annotation.Autowired; -import com.vaadin.flow.component.notification.Notification; +import com.primefactorsolutions.service.EmployeeService; import java.io.ByteArrayInputStream; +import java.time.DayOfWeek; import java.time.LocalDate; +import java.time.format.TextStyle; import java.time.temporal.WeekFields; import java.util.HashMap; import java.util.List; @@ -31,90 +37,217 @@ import java.util.stream.Collectors; @PageTitle("Reporte de Horas Trabajadas") public class ReporteView extends VerticalLayout { + private final EmployeeService employeeService; private final HoursWorkedService hoursWorkedService; private final ReportService reportService; + private final TeamService teamService; - private final ComboBox equipoComboBox = new ComboBox<>("Seleccionar Equipo"); - private final DatePicker semanaPicker = new DatePicker("Seleccionar Semana"); + private final ComboBox equipoComboBox = new ComboBox<>("Seleccionar Equipo"); + private final ComboBox semanaComboBox = new ComboBox<>("Seleccionar Semana"); + private final Grid> grid = new Grid<>(); + private final VerticalLayout headerLayout = new VerticalLayout(); private Anchor downloadLink; + private final Span semanaInfoSpan = new Span(); + + + // Obtener el año actual + private int currentYear = LocalDate.now().getYear(); + @Autowired - public ReporteView(final HoursWorkedService hoursWorkedService, final ReportService reportService) { + public ReporteView(final HoursWorkedService hoursWorkedService, + final ReportService reportService, final TeamService teamService, + final EmployeeService employeeService) { this.hoursWorkedService = hoursWorkedService; this.reportService = reportService; + this.teamService = teamService; + this.employeeService = employeeService; H2 title = new H2("Reporte de Horas Trabajadas"); add(title); - equipoComboBox.setItems("Equipo 1", "Equipo 2", "Equipo 3"); // Opciones de equipo - semanaPicker.setPlaceholder("Seleccione una fecha dentro de la semana deseada"); + List teams = teamService.findAllTeams(); + equipoComboBox.setItems(teams); + equipoComboBox.setItemLabelGenerator(Team::getName); - Button reportButton = new Button("Generar Reporte de Horas Trabajadas", event -> generateHoursWorkedReport()); - HorizontalLayout filtersLayout = new HorizontalLayout(equipoComboBox, semanaPicker, reportButton); + // Configurar el ComboBox de semanas + initializeSemanaComboBox(); + + // Listener para actualizar `semanaInfoSpan` con la selección del usuario en `semanaComboBox` + semanaComboBox.addValueChangeListener(event -> { + String selectedWeek = event.getValue(); + semanaInfoSpan.setText(selectedWeek != null + ? selectedWeek : "Selecciona una semana"); + }); + + Button reportButton = new Button("Generar Reporte de Horas Trabajadas", + event -> generateHoursWorkedReport()); + HorizontalLayout filtersLayout = new HorizontalLayout(equipoComboBox, + semanaComboBox, reportButton); add(filtersLayout); + + // Añadir `headerLayout` al diseño principal para el encabezado dinámico + add(headerLayout); + updateHeaderLayout(null, null); + + grid.addColumn(map -> map.get("ID")).setHeader("ID") + .getElement().getStyle().set("font-weight", "bold"); + grid.addColumn(map -> map.get("Employee ID")).setHeader("Employee ID"); + grid.addColumn(map -> map.get("Empleado")).setHeader("Empleado"); + grid.addColumn(map -> map.get("Horas Trabajadas")).setHeader("Horas Trabajadas"); + grid.addColumn(map -> map.get("Horas Pendientes")).setHeader("Horas Pendientes"); + grid.addColumn(map -> map.get("Observaciones")).setHeader("Observaciones"); + + add(grid); + } + + private void initializeSemanaComboBox() { + int year = LocalDate.now().getYear(); + LocalDate startOfYear = LocalDate.of(year, 1, 5); // Suponemos que la semana comienza el 5 de enero. + + List semanas = startOfYear.datesUntil(LocalDate + .of(year + 1, 1, 1), + java.time.Period.ofWeeks(1)) + .map(date -> { + int weekNumber = date.get(WeekFields.of(DayOfWeek.MONDAY, 1) + .weekOfWeekBasedYear()); + LocalDate startOfWeek = date; + LocalDate endOfWeek = startOfWeek.plusDays(6); + + return String.format("Semana %d: %s - %s", + weekNumber, + startOfWeek.getDayOfMonth() + " de " + startOfWeek.getMonth() + .getDisplayName(TextStyle.FULL, Locale.getDefault()), + endOfWeek.getDayOfMonth() + " de " + endOfWeek.getMonth() + .getDisplayName(TextStyle.FULL, Locale.getDefault()) + ); + }) + .collect(Collectors.toList()); + + semanaComboBox.setItems(semanas); + semanaComboBox.setPlaceholder("Seleccione una semana"); } private void generateHoursWorkedReport() { - String selectedEquipo = equipoComboBox.getValue(); - LocalDate selectedDate = semanaPicker.getValue(); - if (selectedEquipo == null || selectedDate == null) { - Notification.show("Por favor, selecciona un equipo y una semana para generar el reporte.", 3000, Notification.Position.MIDDLE); + Team selectedEquipo = equipoComboBox.getValue(); + String selectedWeek = semanaComboBox.getValue(); + if (selectedEquipo == null || selectedWeek == null) { + Notification.show("Por favor, selecciona un equipo y una semana para generar el reporte.", + 3000, + Notification.Position.MIDDLE); return; } - int weekNumber = getWeekOfYear(selectedDate); + int weekNumber = Integer.parseInt(selectedWeek.split(" ")[1] + .replace(":", "")); + LocalDate selectedDate = LocalDate.now() + .with(WeekFields.of(DayOfWeek.FRIDAY, 1) + .weekOfWeekBasedYear(), weekNumber); + updateHeaderLayout(selectedEquipo, selectedDate); List hoursWorkedList = hoursWorkedService.findAll().stream() - .filter(hw -> hw.getEmployee().getTeam().equals(selectedEquipo) && hw.getWeekNumber() == weekNumber) + .filter(hw -> hw.getEmployee().getTeam().getId() + .equals(selectedEquipo.getId()) && hw.getWeekNumber() == weekNumber) .collect(Collectors.toList()); if (hoursWorkedList.isEmpty()) { Notification.show("No hay horas trabajadas disponibles para generar el reporte.", - 3000, Notification.Position.MIDDLE); + 3000, + Notification.Position.MIDDLE); return; } + List> data = hoursWorkedList.stream() + .map(hoursWorked -> { + Map map = new HashMap<>(); + map.put("ID", hoursWorked.getId().toString()); + map.put("Employee ID", hoursWorked.getEmployee().getId().toString()); + map.put("Empleado", hoursWorked.getEmployee().getFirstName() + " " + + hoursWorked.getEmployee().getLastName()); + map.put("Horas Trabajadas", hoursWorked.getTotalHours()); + map.put("Horas Pendientes", 40 - hoursWorked.getTotalHours()); + map.put("Observaciones", ""); + return map; + }) + .collect(Collectors.toList()); + + grid.setItems(data); + generateExcelDownloadLink(data, weekNumber); + } + + private void updateHeaderLayout(final Team team, final LocalDate dateInWeek) { + headerLayout.removeAll(); + + if (team != null && dateInWeek != null) { + LocalDate startOfWeek = dateInWeek.with(DayOfWeek.FRIDAY); + LocalDate endOfWeek = dateInWeek.with(DayOfWeek.THURSDAY); + int weekNumber = getWeekOfYear(dateInWeek); + + String formattedStartDate = startOfWeek.getDayOfMonth() + " de " + + startOfWeek.getMonth().getDisplayName(TextStyle.FULL, Locale.getDefault()); + String formattedEndDate = endOfWeek.getDayOfMonth() + " de " + + endOfWeek.getMonth().getDisplayName(TextStyle.FULL, Locale.getDefault()); + + headerLayout.add(new Span("Informe " + String.format("%03d", weekNumber) + + "/" + currentYear) {{ + getStyle().set("font-size", "24px"); + getStyle().set("font-weight", "bold"); + }}); + + String teamLeadName = employeeService.getTeamLeadName(team.getId()); + headerLayout.add( + new Span("Asunto: Informe Semanal de Horas Trabajadas") {{ + getStyle().set("font-size", "18px"); + }}, + semanaInfoSpan, + new Span("Horas a cumplir: 40 horas") {{ + getStyle().set("font-size", "18px"); + }}, + new Span("Equipo: " + team.getName()) {{ + getStyle().set("font-size", "18px"); + }}, + new Span("Team Lead: " + teamLeadName) {{ + getStyle().set("font-size", "18px"); + }} + ); + } + } + + private void generateExcelDownloadLink(final List> data, + final int weekNumber) { try { - List headers = List.of("ID", "Employee ID", "Empleado", "Week Number", "Total Hours"); - - List> data = hoursWorkedList.stream() - .map(hoursWorked -> { - Map map = new HashMap<>(); - map.put("ID", hoursWorked.getId().toString()); - map.put("Employee ID", hoursWorked.getEmployee().getId().toString()); - map.put("Empleado", hoursWorked.getEmployee().getFirstName() + " " + hoursWorked.getEmployee().getLastName()); - map.put("Week Number", hoursWorked.getWeekNumber()); - map.put("Total Hours", hoursWorked.getTotalHours()); - return map; - }) - .collect(Collectors.toList()); - - byte[] excelBytes = reportService.writeAsExcel("hours_worked_report", headers, data); + List headers = List.of("ID", "Employee ID", "Empleado", + "Horas Trabajadas", "Horas Pendientes", "Observaciones"); + String selectedTeam = equipoComboBox.getValue().getName(); + byte[] excelBytes = reportService.writeAsExcel("hours_worked_report", + headers, data, selectedTeam, weekNumber, currentYear); StreamResource excelResource = new StreamResource("hours_worked_report.xlsx", () -> new ByteArrayInputStream(excelBytes)); - excelResource.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); - excelResource.setCacheTime(0); - - if (downloadLink != null) { - remove(downloadLink); + if (downloadLink == null) { + downloadLink = new Anchor(excelResource, "Descargar Reporte en Excel"); + downloadLink.getElement().setAttribute("download", true); + add(downloadLink); + } else { + downloadLink.setHref(excelResource); } - - downloadLink = new Anchor(excelResource, "Descargar Reporte de Horas Trabajadas"); - downloadLink.getElement().setAttribute("download", true); - add(downloadLink); - - Notification.show("Reporte de horas trabajadas generado exitosamente.", - 3000, Notification.Position.MIDDLE); - } catch (Exception e) { - Notification.show("Error al generar el reporte de horas trabajadas. Inténtalo de nuevo.", + Notification.show("Error al generar el reporte de horas trabajadas en Excel.", 3000, Notification.Position.MIDDLE); - e.printStackTrace(); } } private int getWeekOfYear(final LocalDate date) { return date.get(WeekFields.of(Locale.getDefault()).weekOfWeekBasedYear()); } + + public int getCurrentYear() { + return currentYear; + } + + // Opcional: Si deseas permitir cambiar el año actual manualmente, agrega un setter + public void setCurrentYear(final int currentYear) { + this.currentYear = currentYear; + } + }