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..a2ddc8b --- /dev/null +++ b/src/main/java/com/primefactorsolutions/model/HoursWorked.java @@ -0,0 +1,61 @@ +package com.primefactorsolutions.model; + +import jakarta.persistence.*; +import jakarta.validation.constraints.AssertTrue; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.time.LocalDate; + +@Data +@Entity +@AllArgsConstructor +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class HoursWorked extends BaseEntity { + + @ManyToOne + @JoinColumn(name = "employee_id", nullable = false) + private Employee employee; + + private LocalDate workDate; + + private int regularHours; + + private int overtimeHours; + + private int weekendHours; + + private int holidayHours; + + @Enumerated(EnumType.STRING) + private WorkType workType; + + @Enumerated(EnumType.STRING) + private ApprovalStatus approvalStatus; + + @Column(columnDefinition = "TEXT") + private String notes; + + public enum WorkType { + ONSITE, REMOTE, HYBRID + } + + public enum ApprovalStatus { + PENDING, APPROVED, REJECTED + } + + @AssertTrue(message = "Las horas no pueden ser negativas") + public boolean areHoursValid() { + return regularHours >= 0 && overtimeHours >= 0 && + weekendHours >= 0 && holidayHours >= 0; + } + + @AssertTrue(message = "La suma de horas no puede superar 24 en un día") + public boolean isTotalHoursValid() { + int totalHours = regularHours + overtimeHours + weekendHours + holidayHours; + return totalHours <= 24; + } +} diff --git a/src/main/java/com/primefactorsolutions/views/HoursWorkedView.java b/src/main/java/com/primefactorsolutions/views/HoursWorkedView.java index 5d5491e..2c3461c 100644 --- a/src/main/java/com/primefactorsolutions/views/HoursWorkedView.java +++ b/src/main/java/com/primefactorsolutions/views/HoursWorkedView.java @@ -1,8 +1,6 @@ package com.primefactorsolutions.views; - import com.primefactorsolutions.model.Employee; import com.primefactorsolutions.service.EmployeeService; -import com.vaadin.flow.component.HasValue; import com.vaadin.flow.component.datepicker.DatePicker; import com.vaadin.flow.component.grid.Grid; import com.vaadin.flow.component.notification.Notification; @@ -11,7 +9,6 @@ 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.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; @@ -27,7 +24,6 @@ import java.time.temporal.WeekFields; import java.util.ArrayList; import java.util.List; import java.util.Locale; -import java.util.stream.IntStream; @SpringComponent @PermitAll @@ -35,49 +31,79 @@ import java.util.stream.IntStream; @PageTitle("Hours Worked") @Route(value = "/hours-worked/me", layout = MainLayout.class) public class HoursWorkedView extends VerticalLayout { - private final List actividades; - private final Grid grid; - private final Grid totalsGrid; + private final List actividades = new ArrayList<>(); + private final Grid grid = new Grid<>(Actividad.class); + private final Grid totalsGrid = new Grid<>(Actividad.class); + private final ComboBox employeeComboBox = new ComboBox<>("Employee"); private LocalDate selectedStartOfWeek; @Autowired - private EmployeeService employeeService; + private final EmployeeService employeeService; private final Label fechasLabel = new Label("Selecciona una semana para ver las fechas."); - public HoursWorkedView() { - actividades = new ArrayList<>(); - grid = new Grid<>(Actividad.class, false); - totalsGrid = new Grid<>(Actividad.class, false); + @Autowired + public HoursWorkedView(final EmployeeService employeeService) { + this.employeeService = employeeService; + configurarVista(); + } - ComboBox semanaComboBox = new ComboBox<>("Selecciona una semana"); - semanaComboBox.setItems(getWeeksOfYear()); - semanaComboBox.addValueChangeListener(event -> { - String selectedWeek = event.getValue(); - if (selectedWeek != null) { - int weekNumber = Integer.parseInt(selectedWeek.split(" ")[1]); - selectedStartOfWeek = getStartOfWeek(weekNumber); + private void setEmployeeComboBoxProperties() { + employeeComboBox.setWidth("250px"); + employeeComboBox.setPlaceholder("Buscar empleado..."); + employeeComboBox.setItems(employeeService.findAllEmployees()); + employeeComboBox.setItemLabelGenerator(employee -> employee.getFirstName() + " " + employee.getLastName()); - LocalDate endOfWeek = selectedStartOfWeek.plusDays(6); - fechasLabel.setText(("Semana del " + selectedStartOfWeek + " al " + endOfWeek)); + employeeComboBox.setAllowCustomValue(false); + employeeComboBox.addCustomValueSetListener(event -> + Notification.show("Selecciona un empleado válido de la lista.") + ); - mostrarActividadesDeLaSemana(); + employeeComboBox.addValueChangeListener(event -> { + Employee selectedEmployee = event.getValue(); + if (selectedEmployee != null) { + Notification.show("Empleado seleccionado: " + + selectedEmployee.getFirstName() + " " + selectedEmployee.getLastName()); + } + }); + } + + 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); } }); - semanaComboBox.setWidth("250px"); ComboBox equipoDropdown = new ComboBox<>("Equipo"); equipoDropdown.setItems("Equipo 1", "Equipo 2", "Equipo 3"); equipoDropdown.setWidth("250px"); - TextField empleadoSearch = new TextField("Empleado (Search)"); - empleadoSearch.setWidth("250px"); - empleadoSearch.addValueChangeListener(event -> { - }); + setEmployeeComboBoxProperties(); - HorizontalLayout filtersLayout = new HorizontalLayout(equipoDropdown, empleadoSearch); + HorizontalLayout filtersLayout = new HorizontalLayout(equipoDropdown, employeeComboBox); filtersLayout.setSpacing(true); + configurarGrid(); + HorizontalLayout actividadFormLayout = configurarFormularioActividades(); + + Button actualizarButton = new Button("Actualizar Totales", event -> actualizarTotales()); + Button guardarButton = new Button("Guardar"); + Button cerrarButton = new Button("Cerrar"); + + HorizontalLayout buttonsLayout = new HorizontalLayout(actualizarButton, guardarButton, cerrarButton); + + add(fechaPicker, fechasLabel, filtersLayout, grid, actividadFormLayout, buttonsLayout, totalsGrid); + configurarTablaTotales(); + } + + 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"); @@ -87,8 +113,9 @@ public class HoursWorkedView extends VerticalLayout { grid.addColumn(Actividad::getSabado).setHeader("Sábado"); grid.addColumn(Actividad::getDomingo).setHeader("Domingo"); grid.addColumn(this::calcularTotalPorDia).setHeader("Total Día").setKey("totalDia"); - grid.setWidth("100%"); + } + private HorizontalLayout configurarFormularioActividades() { TextField actividadNombre = new TextField("Actividad"); TextField lunesHoras = new TextField("Lunes"); TextField martesHoras = new TextField("Martes"); @@ -100,78 +127,75 @@ public class HoursWorkedView extends VerticalLayout { Button agregarActividadButton = new Button("Agregar Actividad", e -> { try { - String nombre = actividadNombre.getValue(); - double lunes = Double.parseDouble(lunesHoras.getValue()); - double martes = Double.parseDouble(martesHoras.getValue()); - double miercoles = Double.parseDouble(miercolesHoras.getValue()); - double jueves = Double.parseDouble(juevesHoras.getValue()); - double viernes = Double.parseDouble(viernesHoras.getValue()); - double sabado = Double.parseDouble(sabadoHoras.getValue()); - double domingo = Double.parseDouble(domingoHoras.getValue()); - Actividad nuevaActividad = new Actividad.Builder() - .nombre(nombre) - .lunes(lunes) - .martes(martes) - .miercoles(miercoles) - .jueves(jueves) - .viernes(viernes) - .sabado(sabado) - .domingo(domingo) + .nombre(actividadNombre.getValue()) + .lunes(Double.parseDouble(lunesHoras.getValue())) + .martes(Double.parseDouble(martesHoras.getValue())) + .miercoles(Double.parseDouble(miercolesHoras.getValue())) + .jueves(Double.parseDouble(juevesHoras.getValue())) + .viernes(Double.parseDouble(viernesHoras.getValue())) + .sabado(Double.parseDouble(sabadoHoras.getValue())) + .domingo(Double.parseDouble(domingoHoras.getValue())) .build(); actividades.add(nuevaActividad); grid.setItems(actividades); actualizarTotales(); - Notification.show("Actividad agregada correctamente"); } catch (NumberFormatException ex) { Notification.show("Error: Por favor ingresa números válidos para las horas."); } }); - HorizontalLayout actividadFormLayout = new HorizontalLayout(actividadNombre, lunesHoras, martesHoras, miercolesHoras, juevesHoras, viernesHoras, sabadoHoras, domingoHoras, agregarActividadButton); - - Button actualizarButton = new Button("Actualizar Totales", event -> actualizarTotales()); - Button guardarButton = new Button("Guardar"); - Button cerrarButton = new Button("Cerrar"); - - HorizontalLayout buttonsLayout = new HorizontalLayout(actualizarButton, guardarButton, cerrarButton); - - add(semanaComboBox, fechasLabel, filtersLayout, grid, actividadFormLayout, buttonsLayout); - add(totalsGrid); - - configurarTablaTotales(); + return new HorizontalLayout( + actividadNombre, lunesHoras, martesHoras, miercolesHoras, + juevesHoras, viernesHoras, sabadoHoras, domingoHoras, agregarActividadButton); } - private List getWeeksOfYear() { - return IntStream.rangeClosed(1, 52) - .mapToObj(week -> "Semana " + week) - .toList(); - } - - private LocalDate getStartOfWeek(int weekNumber) { + private LocalDate getStartOfWeek(final LocalDate date) { WeekFields weekFields = WeekFields.of(Locale.getDefault()); - return LocalDate.now() - .with(weekFields.weekOfYear(), weekNumber) - .with(weekFields.dayOfWeek(), DayOfWeek.MONDAY.getValue()); + return date.with(weekFields.dayOfWeek(), DayOfWeek.MONDAY.getValue()); } - private void mostrarActividadesDeLaSemana() { - if (selectedStartOfWeek != null) { - Notification.show("Mostrando actividades de la semana del " + - selectedStartOfWeek + " al " + selectedStartOfWeek.plusDays(6)); - } - } - - private double calcularTotalPorDia(Actividad actividad) { - return actividad.getLunes() + actividad.getMartes() + actividad.getMiercoles() + - actividad.getJueves() + actividad.getViernes() + actividad.getSabado() + actividad.getDomingo(); + private double calcularTotalPorDia(final Actividad actividad) { + return actividad.getLunes() + actividad.getMartes() + actividad.getMiercoles() + + actividad.getJueves() + actividad.getViernes() + actividad.getSabado() + actividad.getDomingo(); } private void configurarTablaTotales() { + totalsGrid.removeAllColumns(); totalsGrid.addColumn(Actividad::getNombre).setHeader("Descripción"); - totalsGrid.addColumn(Actividad::getLunes).setHeader("Total"); + totalsGrid.addColumn(Actividad::getLunes).setHeader("Lunes"); + totalsGrid.addColumn(Actividad::getMartes).setHeader("Martes"); + totalsGrid.addColumn(Actividad::getMiercoles).setHeader("Miércoles"); + totalsGrid.addColumn(Actividad::getJueves).setHeader("Jueves"); + totalsGrid.addColumn(Actividad::getViernes).setHeader("Viernes"); + totalsGrid.addColumn(Actividad::getSabado).setHeader("Sábado"); + totalsGrid.addColumn(Actividad::getDomingo).setHeader("Domingo"); + totalsGrid.addColumn(this::calcularTotalPorSemana).setHeader("Total"); + + totalsGrid.setItems(calcularTotales()); + } + private double calcularTotalPorSemana(final Actividad actividad) { + return actividad.getLunes() + actividad.getMartes() + actividad.getMiercoles() + + actividad.getJueves() + actividad.getViernes() + actividad.getSabado() + + actividad.getDomingo(); + } + + + private List calcularTotales() { + Actividad totalActividad = new Actividad.Builder() + .nombre("Total Semanal") + .lunes(actividades.stream().mapToDouble(Actividad::getLunes).sum()) + .martes(actividades.stream().mapToDouble(Actividad::getMartes).sum()) + .miercoles(actividades.stream().mapToDouble(Actividad::getMiercoles).sum()) + .jueves(actividades.stream().mapToDouble(Actividad::getJueves).sum()) + .viernes(actividades.stream().mapToDouble(Actividad::getViernes).sum()) + .sabado(actividades.stream().mapToDouble(Actividad::getSabado).sum()) + .domingo(actividades.stream().mapToDouble(Actividad::getDomingo).sum()) + .build(); + + return List.of(totalActividad); } private void actualizarTotales() {