diff --git a/pom.xml b/pom.xml index 194425f..1687fbf 100644 --- a/pom.xml +++ b/pom.xml @@ -186,6 +186,16 @@ viritin 2.8.22 + + org.apache.poi + poi-ooxml + 5.2.3 + + + org.apache.poi + poi-ooxml-schemas + 4.1.2 + com.flowingcode.addons simple-timer diff --git a/src/main/bundles/prod.bundle b/src/main/bundles/prod.bundle index 0fe6623..3338417 100644 Binary files a/src/main/bundles/prod.bundle and b/src/main/bundles/prod.bundle differ diff --git a/src/main/java/com/primefactorsolutions/model/Actividad.java b/src/main/java/com/primefactorsolutions/model/Actividad.java new file mode 100644 index 0000000..f7df96d --- /dev/null +++ b/src/main/java/com/primefactorsolutions/model/Actividad.java @@ -0,0 +1,111 @@ +package com.primefactorsolutions.model; + +public final class Actividad { + private String nombre; + private double lunes; + private double martes; + private double miercoles; + private double jueves; + private double viernes; + private double sabado; + private double domingo; + + public Actividad(final Builder builder) { + this.nombre = builder.nombre; + this.lunes = builder.lunes; + this.martes = builder.martes; + this.miercoles = builder.miercoles; + this.jueves = builder.jueves; + this.viernes = builder.viernes; + this.sabado = builder.sabado; + this.domingo = builder.domingo; + } + + public String getNombre() { + return nombre; + } + + public double getLunes() { + return lunes; + } + + public double getMartes() { + return martes; + } + + public double getMiercoles() { + return miercoles; + } + + public double getJueves() { + return jueves; + } + + public double getViernes() { + return viernes; + } + + public double getSabado() { + return sabado; + } + + public double getDomingo() { + return domingo; + } + + // Builder para crear instancias de Actividad + public static class Builder { + private String nombre; + private double lunes; + private double martes; + private double miercoles; + private double jueves; + private double viernes; + private double sabado; + private double domingo; + + public Builder nombre(final String nombre) { + this.nombre = nombre; + return this; + } + + public Builder lunes(final double horas) { + this.lunes = horas; + return this; + } + + public Builder martes(final double horas) { + this.martes = horas; + return this; + } + + public Builder miercoles(final double horas) { + this.miercoles = horas; + return this; + } + + public Builder jueves(final double horas) { + this.jueves = horas; + return this; + } + + public Builder viernes(final double horas) { + this.viernes = horas; + return this; + } + + public Builder sabado(final double horas) { + this.sabado = horas; + return this; + } + + public Builder domingo(final double horas) { + this.domingo = horas; + return this; + } + + public Actividad build() { + return new Actividad(this); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/primefactorsolutions/model/HoursWorked.java b/src/main/java/com/primefactorsolutions/model/HoursWorked.java new file mode 100644 index 0000000..d02310f --- /dev/null +++ b/src/main/java/com/primefactorsolutions/model/HoursWorked.java @@ -0,0 +1,56 @@ +package com.primefactorsolutions.model; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; + +import java.util.UUID; + +@Entity +public class HoursWorked extends BaseEntity { + @Id + @GeneratedValue(strategy = GenerationType.UUID) + private UUID id; + + @ManyToOne + private Employee employee; + + private int weekNumber; + private double totalHours; + + public HoursWorked() { } + + public UUID getId() { + return id; + } + + public void setId(final UUID id) { + this.id = id; + } + + public Employee getEmployee() { + return employee; + } + + public void setEmployee(final Employee value) { + this.employee = value; + } + + public int getWeekNumber() { + return weekNumber; + } + + public void setWeekNumber(final int weekNumber) { + this.weekNumber = weekNumber; + } + + public double getTotalHours() { + return totalHours; + } + + public void setTotalHours(final double totalHours) { + this.totalHours = totalHours; + } +} diff --git a/src/main/java/com/primefactorsolutions/repositories/HoursWorkedRepository.java b/src/main/java/com/primefactorsolutions/repositories/HoursWorkedRepository.java new file mode 100644 index 0000000..e5ad85b --- /dev/null +++ b/src/main/java/com/primefactorsolutions/repositories/HoursWorkedRepository.java @@ -0,0 +1,10 @@ +package com.primefactorsolutions.repositories; + +import com.primefactorsolutions.model.HoursWorked; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface HoursWorkedRepository extends JpaRepository { + // Puedes definir consultas personalizadas aquí si es necesario. +} diff --git a/src/main/java/com/primefactorsolutions/service/HoursWorkedService.java b/src/main/java/com/primefactorsolutions/service/HoursWorkedService.java new file mode 100644 index 0000000..2da3c4b --- /dev/null +++ b/src/main/java/com/primefactorsolutions/service/HoursWorkedService.java @@ -0,0 +1,35 @@ +package com.primefactorsolutions.service; + +import com.primefactorsolutions.model.HoursWorked; +import com.primefactorsolutions.repositories.HoursWorkedRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class HoursWorkedService { + private final HoursWorkedRepository hoursWorkedRepository; + + @Autowired + public HoursWorkedService(final HoursWorkedRepository hoursWorkedRepository) { + this.hoursWorkedRepository = hoursWorkedRepository; + } + + public List findAll() { + return hoursWorkedRepository.findAll(); + } + + public HoursWorked saveHoursWorked(final HoursWorked hoursWorked) { + return hoursWorkedRepository.save(hoursWorked); + } + + public HoursWorked save(final HoursWorked hoursWorked) { + return hoursWorkedRepository.save(hoursWorked); + } + + public void deleteHoursWorked(final Long id) { + hoursWorkedRepository.deleteById(id); + } +} + diff --git a/src/main/java/com/primefactorsolutions/service/ReportService.java b/src/main/java/com/primefactorsolutions/service/ReportService.java index 0de93fd..beaa21a 100644 --- a/src/main/java/com/primefactorsolutions/service/ReportService.java +++ b/src/main/java/com/primefactorsolutions/service/ReportService.java @@ -2,6 +2,7 @@ package com.primefactorsolutions.service; import com.openhtmltopdf.pdfboxout.PdfBoxRenderer; import com.openhtmltopdf.pdfboxout.PdfRendererBuilder; +import com.primefactorsolutions.repositories.HoursWorkedRepository; import freemarker.template.Configuration; import freemarker.template.DefaultObjectWrapper; import freemarker.template.Template; @@ -9,15 +10,77 @@ import freemarker.template.TemplateExceptionHandler; 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.xssf.usermodel.XSSFWorkbook; import org.jetbrains.annotations.NotNull; import org.springframework.stereotype.Service; import java.io.*; import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Map; import java.util.TimeZone; @Service public class ReportService { + private final HoursWorkedRepository hoursWorkedRepository; + + public ReportService(final HoursWorkedRepository hoursWorkedRepository) { + this.hoursWorkedRepository = hoursWorkedRepository; + } + + // 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) + throws IOException { + return createExcelFile(reportName, headers, data); + } + + private byte[] createExcelFile(final String reportName, final List headers, + final List> data) + throws IOException { + try (Workbook workbook = new XSSFWorkbook(); + ByteArrayOutputStream os = new ByteArrayOutputStream()) { + Sheet sheet = workbook.createSheet(reportName); + + // Crear encabezados + Row headerRow = sheet.createRow(0); + CellStyle headerStyle = workbook.createCellStyle(); + Font headerFont = workbook.createFont(); + headerFont.setBold(true); + headerStyle.setFont(headerFont); + + for (int i = 0; i < headers.size(); i++) { + Cell cell = headerRow.createCell(i); + cell.setCellValue(headers.get(i)); + cell.setCellStyle(headerStyle); + } + + // Crear filas de datos + for (int i = 0; i < data.size(); i++) { + Row dataRow = sheet.createRow(i + 1); + 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 -> { + } + } + } + } + + workbook.write(os); + return os.toByteArray(); + } catch (IOException e) { + System.err.println("Error al generar el archivo Excel: " + e.getMessage()); + throw e; // Propagar la excepción después de registrarla + } + } @SneakyThrows public byte[] writeAsPdf(final String reportName, final Object model) { diff --git a/src/main/java/com/primefactorsolutions/views/HoursWorkedMonthView.java b/src/main/java/com/primefactorsolutions/views/HoursWorkedMonthView.java new file mode 100644 index 0000000..88d86e6 --- /dev/null +++ b/src/main/java/com/primefactorsolutions/views/HoursWorkedMonthView.java @@ -0,0 +1,161 @@ +package com.primefactorsolutions.views; + +import com.primefactorsolutions.model.Employee; +import com.primefactorsolutions.model.Actividad; +import com.primefactorsolutions.service.EmployeeService; +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.Label; +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; +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.context.annotation.Scope; + +import java.time.LocalDate; +import java.util.List; + +@SpringComponent +@PermitAll +@Scope("prototype") +@PageTitle("Hours Worked Month") +@Route(value = "/hours-worked-month/me", layout = MainLayout.class) +public class HoursWorkedMonthView extends VerticalLayout { + private final EmployeeService employeeService; + private final ComboBox employeeComboBox = new ComboBox<>("Empleado"); + private final ComboBox equipoDropdown = new ComboBox<>("Equipo"); + private final Grid grid = new Grid<>(Actividad.class); + + private final Label totalCompletadoLabel = new Label(); + private final Label horasPendientesLabel = new Label(); + private final Label totalAcumuladasLabel = new Label(); + private final Label horasAdeudadasLabel = new Label(); + private final Button actualizarButton = new Button("Actualizar"); + private final Button guardarButton = new Button("Guardar"); + private final Button cerrarButton = new Button("Cerrar"); + + private LocalDate selectedMonth; + + @Autowired + public HoursWorkedMonthView(final EmployeeService employeeService) { + this.employeeService = employeeService; + configurarVista(); + } + + private void configurarVista() { + DatePicker monthPicker = new DatePicker("Selecciona un mes"); + monthPicker.setValue(LocalDate.now()); + monthPicker.addValueChangeListener(event -> { + selectedMonth = event.getValue().withDayOfMonth(1); + //cargarDatosMes(selectedMonth); + }); + + equipoDropdown.setItems("Equipo 1", "Equipo 2", "Equipo 3"); + equipoDropdown.setWidth("250px"); + + setEmployeeComboBoxProperties(); + + configurarGrid(); + + actualizarButton.addClickListener(event -> actualizarDatos()); + guardarButton.addClickListener(event -> guardarActividades()); + cerrarButton.addClickListener(event -> closeView()); + + HorizontalLayout headerLayout = new HorizontalLayout(monthPicker, equipoDropdown, employeeComboBox); + add( + headerLayout, grid, totalCompletadoLabel, + horasPendientesLabel, totalAcumuladasLabel, + horasAdeudadasLabel, actualizarButton, + guardarButton, cerrarButton); + } + + private void setEmployeeComboBoxProperties() { + employeeComboBox.setWidth("250px"); + employeeComboBox.setPlaceholder("Buscar empleado..."); + employeeComboBox.setItems(employeeService.findAllEmployees()); + employeeComboBox.setItemLabelGenerator(employee -> employee.getFirstName() + " " + employee.getLastName()); + } + + private void configurarGrid() { + grid.removeAllColumns(); + grid.addColumn(Actividad::getLunes).setHeader("Lunes"); + grid.addColumn(Actividad::getMartes).setHeader("Martes"); + grid.addColumn(Actividad::getMiercoles).setHeader("Miércoles"); + grid.addColumn(Actividad::getJueves).setHeader("Jueves"); + grid.addColumn(Actividad::getViernes).setHeader("Viernes"); + grid.addColumn(Actividad::getSabado).setHeader("Sábado"); + grid.addColumn(Actividad::getDomingo).setHeader("Domingo"); + grid.addColumn(this::calcularTotalPorDia).setHeader("Total Semanal").setKey("totalSemanal"); + } + +// private void cargarDatosMes(final LocalDate month) { +// List actividadesDelMes = obtenerActividadesDelMes(month); +// grid.setItems(actividadesDelMes); +// +// double totalCompletado = calcularTotalCompletado(actividadesDelMes); +// double horasPendientes = calcularHorasPendientes(totalCompletado); +// double totalAcumuladas = 166; +// double horasAdeudadas = 2; +// +// totalCompletadoLabel.setText("Prom. Hrs/Semana Completadas: " + totalCompletado); +// horasPendientesLabel.setText("Prom. Hrs/Semana Pendientes: " + horasPendientes); +// totalAcumuladasLabel.setText("Total Hrs./Mes Acumuladas: " + totalAcumuladas); +// horasAdeudadasLabel.setText("Total Hrs./Mes Adeudadas: " + horasAdeudadas); +// } + +// private List obtenerActividadesDelMes(final LocalDate month) { +// LocalDate startOfMonth = month.with(TemporalAdjusters.firstDayOfMonth()); +// LocalDate endOfMonth = month.with(TemporalAdjusters.lastDayOfMonth()); +// +// List actividadesDelMes = new ArrayList<>(); +// +// for (LocalDate date = startOfMonth; date.isBefore(endOfMonth.plusDays(1)); date = date.plusDays(1)) { +// Actividad actividad = new Actividad.Builder() +// .lunes(0) +// .martes(0) +// .miercoles(0) +// .jueves(0) +// .viernes(0) +// .sabado(0) +// .domingo(0) +// .build(); +// actividadesDelMes.add(actividad); +// } +// +// return actividadesDelMes; +// } + + private double calcularTotalCompletado(final List actividades) { + return actividades.stream() + .mapToDouble(this::calcularTotalPorDia) + .sum(); + } + + private double calcularTotalPorDia(final Actividad actividad) { + return actividad.getLunes() + actividad.getMartes() + actividad.getMiercoles() + + actividad.getJueves() + actividad.getViernes() + actividad.getSabado() + + actividad.getDomingo(); + } + + private double calcularHorasPendientes(final double totalCompletado) { + return 40 - totalCompletado; + } + + private void actualizarDatos() { + Notification.show("Datos actualizados."); + } + + private void guardarActividades() { + Notification.show("Actividades guardadas correctamente."); + } + + private void closeView() { + getUI().ifPresent(ui -> ui.navigate("")); + } +} diff --git a/src/main/java/com/primefactorsolutions/views/HoursWorkedView.java b/src/main/java/com/primefactorsolutions/views/HoursWorkedView.java index faa4208..2c95054 100644 --- a/src/main/java/com/primefactorsolutions/views/HoursWorkedView.java +++ b/src/main/java/com/primefactorsolutions/views/HoursWorkedView.java @@ -1,19 +1,33 @@ package com.primefactorsolutions.views; - +import com.primefactorsolutions.model.Actividad; +import com.primefactorsolutions.model.Employee; +import com.primefactorsolutions.model.HoursWorked; +import com.primefactorsolutions.service.EmployeeService; +import com.primefactorsolutions.service.HoursWorkedService; import com.vaadin.flow.component.datepicker.DatePicker; +import com.vaadin.flow.component.grid.Grid; +import com.vaadin.flow.component.notification.Notification; import com.vaadin.flow.component.orderedlayout.HorizontalLayout; import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.combobox.ComboBox; -import com.vaadin.flow.component.grid.Grid; import com.vaadin.flow.component.orderedlayout.VerticalLayout; -import com.vaadin.flow.component.html.H2; import com.vaadin.flow.router.PageTitle; 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.context.annotation.Scope; +import com.vaadin.flow.component.html.Label; + + +import java.time.DayOfWeek; import java.time.LocalDate; +import java.time.temporal.IsoFields; +import java.time.temporal.WeekFields; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; @SpringComponent @PermitAll @@ -21,20 +35,107 @@ import java.time.LocalDate; @PageTitle("Hours Worked") @Route(value = "/hours-worked/me", layout = MainLayout.class) public class HoursWorkedView extends VerticalLayout { - public HoursWorkedView() { - H2 title = new H2("Registro de Horas Trabajadas"); + private final List actividades = new ArrayList<>(); + private final Grid grid = new Grid<>(Actividad.class); - DatePicker datePicker = new DatePicker("Selecciona una fecha"); - datePicker.setValue(LocalDate.now()); + private final ComboBox employeeComboBox = new ComboBox<>("Employee"); + private LocalDate selectedStartOfWeek; + private int weekNumber; + + @Autowired + private final EmployeeService employeeService; + + private final Label fechasLabel = new Label("Selecciona una semana para ver las fechas."); + private final Label totalCompletadoLabel = new Label(); + private final Label horasPendientesLabel = new Label(); + + @Autowired + private final HoursWorkedService hoursWorkedService; + public HoursWorkedView(final EmployeeService employeeService, final HoursWorkedService hoursWorkedService) { + this.employeeService = employeeService; + this.hoursWorkedService = hoursWorkedService; + configurarVista(); + cargarDatos(); + } + + private void cargarDatos() { + List listaDeHorasTrabajadas = obtenerDatos(); // Obtenemos la lista aquí + grid.setItems(actividades); + + double totalHoras = calcularTotalHoras(listaDeHorasTrabajadas); // Pasa la lista aquí + } + + private void setEmployeeComboBoxProperties() { + employeeComboBox.setWidth("250px"); + employeeComboBox.setPlaceholder("Buscar empleado..."); + employeeComboBox.setItems(employeeService.findAllEmployees()); + employeeComboBox.setItemLabelGenerator(employee -> employee.getFirstName() + " " + employee.getLastName()); + + employeeComboBox.setAllowCustomValue(false); + employeeComboBox.addCustomValueSetListener(event -> + Notification.show("Selecciona un empleado válido de la lista.") + ); + + employeeComboBox.addValueChangeListener(event -> { + Employee selectedEmployee = event.getValue(); + if (selectedEmployee != null) { + Notification.show("Empleado seleccionado: " + + selectedEmployee.getFirstName() + " " + + selectedEmployee.getLastName()); + } + }); + } + + private int getWeekOfYear(final LocalDate date) { + return date.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR); + } + + private void configurarVista() { + DatePicker fechaPicker = new DatePicker("Selecciona una fecha"); + fechaPicker.addValueChangeListener(event -> { + LocalDate selectedDate = event.getValue(); + if (selectedDate != null) { + selectedStartOfWeek = getStartOfWeek(selectedDate); + LocalDate endOfWeek = selectedStartOfWeek.plusDays(6); + fechasLabel.setText("Semana del " + selectedStartOfWeek + " al " + endOfWeek); + weekNumber = getWeekOfYear(selectedDate); + } + }); + + Button verMesButton = new Button("Ver Mes", event -> { + getUI().ifPresent(ui -> ui.navigate(HoursWorkedMonthView.class)); + }); ComboBox equipoDropdown = new ComboBox<>("Equipo"); - equipoDropdown.setItems("Equipo 1", "Equipo 2", "Equipo 3"); // Ejemplo de datos + equipoDropdown.setItems("Equipo 1", "Equipo 2", "Equipo 3"); + equipoDropdown.setWidth("250px"); - TextField empleadoSearch = new TextField("Empleado (Search)"); + setEmployeeComboBoxProperties(); - HorizontalLayout filtersLayout = new HorizontalLayout(equipoDropdown, empleadoSearch); + HorizontalLayout filtersLayout = new HorizontalLayout(equipoDropdown, employeeComboBox); + filtersLayout.setSpacing(true); - Grid grid = new Grid<>(Actividad.class, false); + configurarGrid(); + HorizontalLayout actividadFormLayout = configurarFormularioActividades(); + + Button actualizarButton = new Button("Actualizar Totales", event -> actualizarTotales()); + Button guardarButton = new Button("Guardar", event -> guardarActividades()); + Button cerrarButton = new Button("Cerrar", event -> this.closeView()); + + HorizontalLayout buttonsLayout = new HorizontalLayout(actualizarButton, guardarButton, + cerrarButton, verMesButton); + + VerticalLayout totalesLayout = new VerticalLayout(totalCompletadoLabel, horasPendientesLabel); + totalesLayout.setSpacing(true); + totalesLayout.setPadding(true); + + add(fechaPicker, fechasLabel, filtersLayout, grid, actividadFormLayout, buttonsLayout, totalesLayout); + + } + + private void configurarGrid() { + grid.removeAllColumns(); + grid.setItems(actividades); grid.addColumn(Actividad::getNombre).setHeader("Actividad"); grid.addColumn(Actividad::getLunes).setHeader("Lunes"); grid.addColumn(Actividad::getMartes).setHeader("Martes"); @@ -43,155 +144,127 @@ public class HoursWorkedView extends VerticalLayout { grid.addColumn(Actividad::getViernes).setHeader("Viernes"); grid.addColumn(Actividad::getSabado).setHeader("Sábado"); grid.addColumn(Actividad::getDomingo).setHeader("Domingo"); - - grid.setItems( - new Actividad.Builder() - .nombre("Actividad 1") - .lunes(3) - .martes(3) - .miercoles(3) - .jueves(3) - .viernes(3) - .sabado(1) - .domingo(2) - .build(), - new Actividad.Builder() - .nombre("Actividad 2") - .lunes(2) - .martes(2) - .miercoles(2) - .jueves(2) - .viernes(2) - .sabado(0) - .domingo(1) - .build(), - new Actividad.Builder() - .nombre("Meeting 1") - .lunes(0) - .martes(0.5) - .miercoles(0.5) - .jueves(0) - .viernes(0) - .sabado(0.5) - .domingo(0) - .build() - ); - - Button actualizarButton = new Button("Actualizar"); - Button guardarButton = new Button("Guardar"); - Button cerrarButton = new Button("Cerrar"); - - HorizontalLayout buttonsLayout = new HorizontalLayout(actualizarButton, guardarButton, cerrarButton); - - add(title, datePicker, filtersLayout, grid, buttonsLayout); + grid.addColumn(this::calcularTotalPorDia).setHeader("Total Día").setKey("totalDia"); } - public static final class Actividad { - private final String nombre; - private final double lunes; - private final double martes; - private final double miercoles; - private final double jueves; - private final double viernes; - private final double sabado; - private final double domingo; + private HorizontalLayout configurarFormularioActividades() { + TextField actividadNombre = new TextField("Actividad"); + actividadNombre.setWidth("200px"); - private Actividad(final Builder builder) { - this.nombre = builder.nombre; - this.lunes = builder.lunes; - this.martes = builder.martes; - this.miercoles = builder.miercoles; - this.jueves = builder.jueves; - this.viernes = builder.viernes; - this.sabado = builder.sabado; - this.domingo = builder.domingo; + TextField lunesHoras = crearCampoHora("Lunes"); + TextField martesHoras = crearCampoHora("Martes"); + TextField miercolesHoras = crearCampoHora("Miércoles"); + TextField juevesHoras = crearCampoHora("Jueves"); + TextField viernesHoras = crearCampoHora("Viernes"); + TextField sabadoHoras = crearCampoHora("Sábado"); + TextField domingoHoras = crearCampoHora("Domingo"); + + Button agregarActividadButton = new Button("Agregar Actividad", e -> { + try { + Actividad nuevaActividad = new Actividad.Builder() + .nombre(actividadNombre.getValue()) + .lunes(parseHoras(lunesHoras.getValue())) + .martes(parseHoras(martesHoras.getValue())) + .miercoles(parseHoras(miercolesHoras.getValue())) + .jueves(parseHoras(juevesHoras.getValue())) + .viernes(parseHoras(viernesHoras.getValue())) + .sabado(parseHoras(sabadoHoras.getValue())) + .domingo(parseHoras(domingoHoras.getValue())) + .build(); + + actividades.add(nuevaActividad); + grid.setItems(actividades); + actualizarTotales(); + Notification.show("Actividad agregada correctamente"); + // Limpiar los campos de entrada + actividadNombre.clear(); + lunesHoras.clear(); + martesHoras.clear(); + miercolesHoras.clear(); + juevesHoras.clear(); + viernesHoras.clear(); + sabadoHoras.clear(); + domingoHoras.clear(); + } catch (NumberFormatException ex) { + Notification.show("Error: Por favor ingresa números válidos para las horas."); + } + }); + + return new HorizontalLayout( + actividadNombre, lunesHoras, martesHoras, miercolesHoras, + juevesHoras, viernesHoras, sabadoHoras, domingoHoras, agregarActividadButton); + } + + private TextField crearCampoHora(final String placeholder) { + TextField field = new TextField(placeholder); + field.setWidth("80px"); + field.setPlaceholder("0.0"); + return field; + } + + private double parseHoras(final String value) { + if (value == null || value.trim().isEmpty()) { + return 0.0; + } + return Double.parseDouble(value); + } + + private LocalDate getStartOfWeek(final LocalDate date) { + WeekFields weekFields = WeekFields.of(Locale.getDefault()); + return date.with(weekFields.dayOfWeek(), DayOfWeek.MONDAY.getValue()); + } + + private double calcularTotalPorDia(final Actividad actividad) { + return actividad.getLunes() + actividad.getMartes() + actividad.getMiercoles() + + actividad.getJueves() + actividad.getViernes() + actividad.getSabado() + actividad.getDomingo(); + } + + private void actualizarTotales() { + double totalSemanaCompletada = actividades.stream() + .mapToDouble(this::calcularTotalPorDia) + .sum(); + double horasPendientes = 40 - totalSemanaCompletada; + + totalCompletadoLabel.setText("Total Hrs/Semana Completadas: " + totalSemanaCompletada); + horasPendientesLabel.setText("Horas Pendientes: " + horasPendientes); + } + + private void guardarActividades() { + Employee selectedEmployee = employeeComboBox.getValue(); + + if (selectedEmployee == null) { + Notification.show("Por favor, selecciona un empleado antes de guardar."); + return; } - public static class Builder { - private String nombre; - private double lunes; - private double martes; - private double miercoles; - private double jueves; - private double viernes; - private double sabado; - private double domingo; + double totalHorasSemana = actividades.stream() + .mapToDouble(this::calcularTotalPorDia) + .sum(); - public Builder nombre(final String nombre) { - this.nombre = nombre; - return this; - } + HoursWorked hoursWorked = new HoursWorked(); + hoursWorked.setEmployee(selectedEmployee); + hoursWorked.setWeekNumber(weekNumber); + hoursWorked.setTotalHours(totalHorasSemana); - public Builder lunes(final double lunes) { - this.lunes = lunes; - return this; - } - - public Builder martes(final double martes) { - this.martes = martes; - return this; - } - - public Builder miercoles(final double miercoles) { - this.miercoles = miercoles; - return this; - } - - public Builder jueves(final double jueves) { - this.jueves = jueves; - return this; - } - - public Builder viernes(final double viernes) { - this.viernes = viernes; - return this; - } - - public Builder sabado(final double sabado) { - this.sabado = sabado; - return this; - } - - public Builder domingo(final double domingo) { - this.domingo = domingo; - return this; - } - - public Actividad build() { - return new Actividad(this); - } - } - - public String getNombre() { - return nombre; - } - - public double getLunes() { - return lunes; - } - - public double getMartes() { - return martes; - } - - public double getMiercoles() { - return miercoles; - } - - public double getJueves() { - return jueves; - } - - public double getViernes() { - return viernes; - } - - public double getSabado() { - return sabado; - } - - public double getDomingo() { - return domingo; + try { + hoursWorkedService.saveHoursWorked(hoursWorked); // Usa saveHoursWorked directamente + Notification.show("Actividades guardadas correctamente."); + } catch (Exception e) { + Notification.show("Error al guardar actividades: " + e.getMessage()); } } -} + + private double calcularTotalHoras(final List listaDeHorasTrabajadas) { + return listaDeHorasTrabajadas.stream() + .mapToDouble(HoursWorked::getTotalHours) + .sum(); + } + + private List obtenerDatos() { + return new ArrayList<>(); + } + + private void closeView() { + getUI().ifPresent(ui -> ui.navigate(HoursWorkedView.class)); + } +} \ No newline at end of file diff --git a/src/main/java/com/primefactorsolutions/views/ReporteView.java b/src/main/java/com/primefactorsolutions/views/ReporteView.java new file mode 100644 index 0000000..1416a56 --- /dev/null +++ b/src/main/java/com/primefactorsolutions/views/ReporteView.java @@ -0,0 +1,87 @@ +package com.primefactorsolutions.views; + +import com.primefactorsolutions.model.HoursWorked; +import com.primefactorsolutions.service.HoursWorkedService; +import com.primefactorsolutions.service.ReportService; +import com.vaadin.flow.component.button.Button; +import com.vaadin.flow.component.html.Anchor; +import com.vaadin.flow.component.html.H2; +import com.vaadin.flow.component.orderedlayout.VerticalLayout; +import com.vaadin.flow.router.PageTitle; +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 java.io.ByteArrayInputStream; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@PermitAll +@Route(value = "/reportes", layout = MainLayout.class) +@PageTitle("Reporte de Horas Trabajadas") +public class ReporteView extends VerticalLayout { + + private final HoursWorkedService hoursWorkedService; + private final ReportService reportService; + + @Autowired + public ReporteView(final HoursWorkedService hoursWorkedService, final ReportService reportService) { + this.hoursWorkedService = hoursWorkedService; + this.reportService = reportService; + + H2 title = new H2("Reporte de Horas Trabajadas"); + add(title); + + Button reportButton = new Button("Generar Reporte de Horas Trabajadas", event -> generateHoursWorkedReport()); + add(reportButton); + } + + private void generateHoursWorkedReport() { + List hoursWorkedList = hoursWorkedService.findAll(); // Obtener la lista de HoursWorked + + if (hoursWorkedList.isEmpty()) { + Notification.show("No hay horas trabajadas disponibles para generar el reporte.", + 3000, Notification.Position.MIDDLE); + return; + } + + try { + List headers = List.of("ID", "Employee ID", "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("Week Number", hoursWorked.getWeekNumber()); + map.put("Total Hours", hoursWorked.getTotalHours()); + return map; + }) + .collect(Collectors.toList()); + + byte[] excelBytes = reportService.writeAsExcel("hours_worked_report", headers, data); + + StreamResource excelResource = new StreamResource("hours_worked_report.xlsx", + () -> new ByteArrayInputStream(excelBytes)); + excelResource.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + excelResource.setCacheTime(0); + + Anchor 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.", + 3000, Notification.Position.MIDDLE); + e.printStackTrace(); + } + } + +}