diff --git a/src/main/bundles/prod.bundle b/src/main/bundles/prod.bundle index b05a96c..3ca2c8c 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/Employee.java b/src/main/java/com/primefactorsolutions/model/Employee.java index f3e2a7a..afbca9b 100644 --- a/src/main/java/com/primefactorsolutions/model/Employee.java +++ b/src/main/java/com/primefactorsolutions/model/Employee.java @@ -3,11 +3,9 @@ package com.primefactorsolutions.model; import com.google.common.collect.Lists; import jakarta.persistence.*; import jakarta.validation.constraints.*; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; +import lombok.*; import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import java.math.BigDecimal; @@ -102,8 +100,8 @@ public class Employee extends BaseEntity implements UserDetails { private String bankName; @Pattern(regexp = "^[0-9]+$", message = "El número de cuenta debe contener solo números") private String accountNumber; + @Setter private String customContractType; - private String gpss; private String sss; @Pattern(regexp = "^[a-zA-Z ]+$", message = "Los derechohabientes solo deben contener letras") @@ -115,13 +113,9 @@ public class Employee extends BaseEntity implements UserDetails { @Enumerated(EnumType.STRING) private Status status; - public void setCustomContractType(final String customContractType) { - this.customContractType = customContractType; - } - @Override public Collection getAuthorities() { - return Lists.newArrayList(); + return Lists.newArrayList(new SimpleGrantedAuthority("ROLE_" + this.role.name())); } @Override @@ -154,13 +148,26 @@ public class Employee extends BaseEntity implements UserDetails { return true; } + @Enumerated(EnumType.STRING) + private MaritalStatus maritalStatus; + @Enumerated(EnumType.STRING) + private Gender gender; + @Enumerated(EnumType.STRING) + private ContractType contractType; + @Size(max = 255, message = "El detalle del contrato no debe exceder 255 caracteres") + private String otherContractDetail; + @Enumerated(EnumType.STRING) + private Role role = Role.USER; + public enum Status { ACTIVE, INACTIVE } - @Enumerated(EnumType.STRING) - private MaritalStatus maritalStatus; + public enum Gender { + MALE, + FEMALE + } public enum MaritalStatus { SINGLE, @@ -169,20 +176,6 @@ public class Employee extends BaseEntity implements UserDetails { DIVORCED } - @Enumerated(EnumType.STRING) - private Gender gender; - - public enum Gender { - MALE, - FEMALE - } - - @Enumerated(EnumType.STRING) - private ContractType contractType; - - @Size(max = 255, message = "El detalle del contrato no debe exceder 255 caracteres") - private String otherContractDetail; - public enum ContractType { CONTRATO_LABORAL, CONTRATO_CIVIL_O_SERVICIOS, diff --git a/src/main/java/com/primefactorsolutions/model/HoursWorked.java b/src/main/java/com/primefactorsolutions/model/HoursWorked.java index 031bef8..87efef0 100644 --- a/src/main/java/com/primefactorsolutions/model/HoursWorked.java +++ b/src/main/java/com/primefactorsolutions/model/HoursWorked.java @@ -1,15 +1,11 @@ package com.primefactorsolutions.model; import jakarta.persistence.*; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; +import lombok.*; import java.time.LocalDate; -import java.time.temporal.WeekFields; +import java.time.temporal.IsoFields; import java.util.List; -import java.util.Locale; @Data @Entity @@ -17,31 +13,17 @@ import java.util.Locale; @NoArgsConstructor @EqualsAndHashCode(callSuper = true) public class HoursWorked extends BaseEntity { - @ManyToOne - @JoinColumn(name = "employee_id", nullable = true) - private Employee employee; - @ManyToOne - @JoinColumn(name = "team_id", nullable = true) - private Team team; - - private int weekNumber; + private String task; + private String activity; private LocalDate date; - private String actividad; private double hours; - private double horaspendientes; - private double totalHours; - - private String tareaEspecifica; - - public String getTareaEspecifica() { - return tareaEspecifica; - } - - public void setTareaEspecifica(final String tareaEspecifica) { - this.tareaEspecifica = tareaEspecifica; - } - + @ManyToOne + @JoinColumn(name = "employee_id") + private Employee employee; + @ManyToOne + @JoinColumn(name = "team_id") + private Team team; public static double calculateTotalHours(final List activities) { return activities.stream() @@ -54,73 +36,7 @@ public class HoursWorked extends BaseEntity { return Math.max(0, 40 - totalHoursWorked); } - public Employee getEmployee() { - return employee; - } - - public void setEmployee(final Employee employee) { - this.employee = employee; - } - public int getWeekNumber() { - return weekNumber; + return date.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR); } - - public void setWeekNumber(final int weekNumber) { - this.weekNumber = weekNumber; - } - public LocalDate getDate() { - return date; - } - - public void setDate(final LocalDate date) { - this.date = date; - if (date != null) { - WeekFields weekFields = WeekFields.of(Locale.getDefault()); - this.weekNumber = date.get(weekFields.weekOfWeekBasedYear()); - } - } - - public String getActividad() { - return actividad; - } - - public void setActividad(final String actividad) { - this.actividad = actividad; - } - - public double getHours() { - return hours; - } - - public void setHours(final double hours) { - this.hours = hours; - } - - public double getTotalHours() { - double total = this.getHours(); - return totalHours + total; - } - - public void setTotalHours(final double totalHours) { - this.totalHours = totalHours; - } - - public Team getTeam() { - return team; - } - - public void setTeam(final Team team) { - this.team = team; - } - - public double getHoraspendientes() { - //double horasTrabajadas = this.getTotalHours() + this.getHorasTareasEspecificas(); - return 40; - } - - public void setHoraspendientes(final double horaspendientes) { - this.horaspendientes = horaspendientes; - } - } diff --git a/src/main/java/com/primefactorsolutions/model/TimeOffRequestType.java b/src/main/java/com/primefactorsolutions/model/TimeOffRequestType.java index 3bf6fc7..d3537e4 100644 --- a/src/main/java/com/primefactorsolutions/model/TimeOffRequestType.java +++ b/src/main/java/com/primefactorsolutions/model/TimeOffRequestType.java @@ -1,7 +1,6 @@ package com.primefactorsolutions.model; public enum TimeOffRequestType { - TODOS, AÑO_NUEVO, LUNES_CARNAVAL, MARTES_CARNAVAL, diff --git a/src/main/java/com/primefactorsolutions/repositories/HoursWorkedRepository.java b/src/main/java/com/primefactorsolutions/repositories/HoursWorkedRepository.java index 8662eb2..286d82a 100644 --- a/src/main/java/com/primefactorsolutions/repositories/HoursWorkedRepository.java +++ b/src/main/java/com/primefactorsolutions/repositories/HoursWorkedRepository.java @@ -7,10 +7,6 @@ import java.time.LocalDate; import java.util.List; import java.util.UUID; - public interface HoursWorkedRepository extends JpaRepository { - List findByWeekNumber(int weekNumber); - List findByDate(LocalDate date); - List findByEmployeeIdAndWeekNumber(UUID employeeId, int weekNumber); + List findByEmployeeIdAndDateBetween(UUID employeeId, LocalDate from, LocalDate to); } - diff --git a/src/main/java/com/primefactorsolutions/service/HoursWorkedService.java b/src/main/java/com/primefactorsolutions/service/HoursWorkedService.java index 36395bf..6f6fc42 100644 --- a/src/main/java/com/primefactorsolutions/service/HoursWorkedService.java +++ b/src/main/java/com/primefactorsolutions/service/HoursWorkedService.java @@ -2,11 +2,12 @@ package com.primefactorsolutions.service; import com.primefactorsolutions.model.HoursWorked; import com.primefactorsolutions.repositories.HoursWorkedRepository; -import org.apache.commons.beanutils.BeanComparator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.time.LocalDate; +import java.time.Year; +import java.time.temporal.WeekFields; import java.util.*; @Service @@ -22,78 +23,26 @@ public class HoursWorkedService { return hoursWorkedRepository.findAll(); } - public double getTotalHoursWorkedByEmployeeForWeek(final UUID employeeId, final int weekNumber) { - List hoursWorkedList = hoursWorkedRepository.findByWeekNumber(weekNumber); - return hoursWorkedList.stream() - .filter(hw -> hw.getEmployee().getId().equals(employeeId)) - .mapToDouble(HoursWorked::getTotalHours) - .sum(); - } - - public HoursWorked findHoursWorked(final UUID id) { - Optional hoursWorked = hoursWorkedRepository.findById(id); - HoursWorked hw = hoursWorked.get(); - return hw; - } - - public HoursWorked saveHoursWorked(final HoursWorked hoursWorked) { - return hoursWorkedRepository.save(hoursWorked); - } - public HoursWorked save(final HoursWorked hoursWorked) { return hoursWorkedRepository.save(hoursWorked); } - public double getTotalHoursForEmployee(final UUID employeeId, final int weekNumber) { - List activities = hoursWorkedRepository.findByEmployeeIdAndWeekNumber(employeeId, weekNumber); - return HoursWorked.calculateTotalHours(activities); - } - - public double getPendingHoursForEmployee(final UUID employeeId, final int weekNumber) { - List activities = hoursWorkedRepository.findByEmployeeIdAndWeekNumber(employeeId, weekNumber); - return HoursWorked.calculatePendingHours(activities); - } - - public List findByWeekNumber(final int weekNumber) { - return hoursWorkedRepository.findByWeekNumber(weekNumber); - } - - public List findByDate(final LocalDate date) { - return hoursWorkedRepository.findByDate(date); - } - - public List findByDateAndWeekNumber(final LocalDate date, final int weekNumber) { - return hoursWorkedRepository.findByDate(date); - } - - public List findHoursWorkeds( - final int start, final int pageSize, final String sortProperty, final boolean asc) { - List hoursWorkeds = hoursWorkedRepository.findAll(); - - int end = Math.min(start + pageSize, hoursWorkeds.size()); - hoursWorkeds.sort(new BeanComparator<>(sortProperty)); - - if (!asc) { - Collections.reverse(hoursWorkeds); - } - - return hoursWorkeds.subList(start, end); - } - - public List findHoursWorkeds(final int start, final int pageSize) { - List hoursWorkeds = hoursWorkedRepository.findAll(); - - int end = Math.min(start + pageSize, hoursWorkeds.size()); - return hoursWorkeds.subList(start, end); - } - public HoursWorked getHoursWorked(final UUID id) { final Optional hoursWorked = hoursWorkedRepository.findById(id); - return hoursWorked.get(); + return hoursWorked.orElse(null); } public List findListHoursWorkedEmployee(final UUID employeeId, final int weekNumber) { - return hoursWorkedRepository.findByEmployeeIdAndWeekNumber(employeeId, weekNumber); + final LocalDate from = getFirstDayOfWeek(weekNumber); + final LocalDate to = from.plusDays(7); + + return hoursWorkedRepository.findByEmployeeIdAndDateBetween(employeeId, from, to); } + private static LocalDate getFirstDayOfWeek(final int weekNumber) { + return LocalDate + .of(Year.now().getValue(), 2, 1) + .with(WeekFields.of(Locale.US).getFirstDayOfWeek()) + .with(WeekFields.of(Locale.US).weekOfWeekBasedYear(), weekNumber); + } } diff --git a/src/main/java/com/primefactorsolutions/service/ReportService.java b/src/main/java/com/primefactorsolutions/service/ReportService.java index 90694ed..6167d73 100644 --- a/src/main/java/com/primefactorsolutions/service/ReportService.java +++ b/src/main/java/com/primefactorsolutions/service/ReportService.java @@ -3,7 +3,6 @@ package com.primefactorsolutions.service; import com.openhtmltopdf.pdfboxout.PdfBoxRenderer; import com.openhtmltopdf.pdfboxout.PdfRendererBuilder; import com.primefactorsolutions.model.Employee; -import com.primefactorsolutions.repositories.HoursWorkedRepository; import freemarker.template.Configuration; import freemarker.template.DefaultObjectWrapper; import freemarker.template.Template; @@ -25,13 +24,9 @@ import java.util.TimeZone; @Service public class ReportService { - private final HoursWorkedRepository hoursWorkedRepository; - - public ReportService(final HoursWorkedRepository hoursWorkedRepository) { - this.hoursWorkedRepository = hoursWorkedRepository; + public 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 String selectedTeam, final int weekNumber, final int currentYear) diff --git a/src/main/java/com/primefactorsolutions/views/AssessmentsListView.java b/src/main/java/com/primefactorsolutions/views/AssessmentsListView.java index 74016fd..1ee7189 100644 --- a/src/main/java/com/primefactorsolutions/views/AssessmentsListView.java +++ b/src/main/java/com/primefactorsolutions/views/AssessmentsListView.java @@ -18,6 +18,7 @@ import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; import com.vaadin.flow.shared.Registration; import com.vaadin.flow.spring.annotation.SpringComponent; +import com.vaadin.flow.spring.security.AuthenticationContext; import jakarta.annotation.security.PermitAll; import org.springframework.context.annotation.Scope; import org.vaadin.addon.stefan.clipboard.ClientsideClipboard; @@ -32,7 +33,9 @@ import java.util.stream.Stream; @PermitAll public class AssessmentsListView extends BaseView { - public AssessmentsListView(final AssessmentService assessmentService) { + public AssessmentsListView(final AuthenticationContext authenticationContext, + final AssessmentService assessmentService) { + super(authenticationContext); final HorizontalLayout hl = new HorizontalLayout(); final Button addAssessment = new Button("Add Assessment"); addAssessment.addClickListener((ComponentEventListener>) buttonClickEvent -> { diff --git a/src/main/java/com/primefactorsolutions/views/BaseView.java b/src/main/java/com/primefactorsolutions/views/BaseView.java index 48a17d8..91e9c81 100644 --- a/src/main/java/com/primefactorsolutions/views/BaseView.java +++ b/src/main/java/com/primefactorsolutions/views/BaseView.java @@ -2,15 +2,24 @@ package com.primefactorsolutions.views; import com.vaadin.flow.component.html.Main; import com.vaadin.flow.component.orderedlayout.VerticalLayout; +import com.vaadin.flow.spring.security.AuthenticationContext; import lombok.Getter; +import static com.primefactorsolutions.views.util.AuthUtils.isAdmin; + @Getter -public class BaseView extends Main { +public abstract class BaseView extends Main { private final VerticalLayout currentPageLayout; + private final AuthenticationContext authenticationContext; - public BaseView() { + public BaseView(final AuthenticationContext authenticationContext) { + this.authenticationContext = authenticationContext; currentPageLayout = new VerticalLayout(); add(currentPageLayout); } + + protected boolean isRoleAdmin() { + return isAdmin(this.authenticationContext); + } } diff --git a/src/main/java/com/primefactorsolutions/views/CalendarView.java b/src/main/java/com/primefactorsolutions/views/CalendarView.java deleted file mode 100644 index c8d02fb..0000000 --- a/src/main/java/com/primefactorsolutions/views/CalendarView.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.primefactorsolutions.views; - -public class CalendarView { -} diff --git a/src/main/java/com/primefactorsolutions/views/CandidatesListView.java b/src/main/java/com/primefactorsolutions/views/CandidatesListView.java index fe97ab1..f2cb5e2 100644 --- a/src/main/java/com/primefactorsolutions/views/CandidatesListView.java +++ b/src/main/java/com/primefactorsolutions/views/CandidatesListView.java @@ -15,6 +15,7 @@ import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; import com.vaadin.flow.shared.Registration; import com.vaadin.flow.spring.annotation.SpringComponent; +import com.vaadin.flow.spring.security.AuthenticationContext; import jakarta.annotation.security.PermitAll; import org.springframework.context.annotation.Scope; import org.vaadin.firitin.components.grid.VGrid; @@ -28,8 +29,9 @@ import java.util.stream.Stream; @PermitAll public class CandidatesListView extends BaseView { - public CandidatesListView(final CandidateService candidateService) { - + public CandidatesListView(final AuthenticationContext authenticationContext, + final CandidateService candidateService) { + super(authenticationContext); final HorizontalLayout hl = new HorizontalLayout(); final Button addCandidate = new Button("Add Candidate"); addCandidate.addClickListener((ComponentEventListener>) buttonClickEvent -> { diff --git a/src/main/java/com/primefactorsolutions/views/DocumentsListView.java b/src/main/java/com/primefactorsolutions/views/DocumentsListView.java index 312a3f3..f3df80c 100644 --- a/src/main/java/com/primefactorsolutions/views/DocumentsListView.java +++ b/src/main/java/com/primefactorsolutions/views/DocumentsListView.java @@ -26,6 +26,7 @@ import com.vaadin.flow.router.Route; import com.vaadin.flow.server.StreamRegistration; import com.vaadin.flow.server.StreamResource; import com.vaadin.flow.spring.annotation.SpringComponent; +import com.vaadin.flow.spring.security.AuthenticationContext; import jakarta.annotation.security.PermitAll; import org.springframework.context.annotation.Scope; import org.vaadin.firitin.components.grid.PagingGrid; @@ -48,7 +49,10 @@ public class DocumentsListView extends BaseView { private ComboBox employeeFilter; private ComboBox documentTypeFilter; - public DocumentsListView(final DocumentService documentService, final EmployeeService employeeService) { + public DocumentsListView(final AuthenticationContext authenticationContext, + final DocumentService documentService, + final EmployeeService employeeService) { + super(authenticationContext); this.documentService = documentService; this.employeeService = employeeService; initializeView(); diff --git a/src/main/java/com/primefactorsolutions/views/EmployeeView.java b/src/main/java/com/primefactorsolutions/views/EmployeeView.java index 2bef270..66ba64d 100644 --- a/src/main/java/com/primefactorsolutions/views/EmployeeView.java +++ b/src/main/java/com/primefactorsolutions/views/EmployeeView.java @@ -271,7 +271,6 @@ public class EmployeeView extends BeanValidationForm implements HasUrl int ages = currentYear - birthYear; age.setValue(String.valueOf(ages)); birthday.setInvalid(ages < 18); - System.out.println(age); } } diff --git a/src/main/java/com/primefactorsolutions/views/EmployeesListView.java b/src/main/java/com/primefactorsolutions/views/EmployeesListView.java index 387de71..f050784 100644 --- a/src/main/java/com/primefactorsolutions/views/EmployeesListView.java +++ b/src/main/java/com/primefactorsolutions/views/EmployeesListView.java @@ -8,12 +8,13 @@ import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; import com.vaadin.flow.server.StreamResource; import com.vaadin.flow.spring.annotation.SpringComponent; +import com.vaadin.flow.spring.security.AuthenticationContext; +import jakarta.annotation.security.RolesAllowed; import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.vaadin.firitin.components.grid.PagingGrid; import com.vaadin.flow.component.grid.GridSortOrder; import com.vaadin.flow.data.provider.SortDirection; -import jakarta.annotation.security.PermitAll; import org.springframework.context.annotation.Scope; import java.io.ByteArrayInputStream; @@ -25,13 +26,14 @@ import java.util.List; @Scope("prototype") @PageTitle("Employees") @Route(value = "/employees", layout = MainLayout.class) -@PermitAll +@RolesAllowed("ROLE_ADMIN") public class EmployeesListView extends BaseView { private final EmployeeService employeeService; private final PagingGrid table = new PagingGrid<>(Employee.class); - public EmployeesListView(final EmployeeService employeeService) { + public EmployeesListView(final AuthenticationContext authenticationContext, final EmployeeService employeeService) { + super(authenticationContext); this.employeeService = employeeService; setupView(); refreshGrid(); diff --git a/src/main/java/com/primefactorsolutions/views/HoursWorkedView.java b/src/main/java/com/primefactorsolutions/views/HoursWorkedView.java deleted file mode 100644 index 4df236e..0000000 --- a/src/main/java/com/primefactorsolutions/views/HoursWorkedView.java +++ /dev/null @@ -1,307 +0,0 @@ -package com.primefactorsolutions.views; - -import com.primefactorsolutions.model.Employee; -import com.primefactorsolutions.model.HoursWorked; -import com.primefactorsolutions.model.Team; -import com.primefactorsolutions.service.EmployeeService; -import com.primefactorsolutions.service.HoursWorkedService; -import com.primefactorsolutions.service.TeamService; -import com.vaadin.flow.component.Component; -import com.vaadin.flow.component.html.H2; -import com.vaadin.flow.component.html.Label; -import com.vaadin.flow.component.notification.Notification; -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.router.*; -import com.vaadin.flow.spring.annotation.SpringComponent; -import jakarta.annotation.security.PermitAll; -import org.springframework.context.annotation.Scope; -import org.vaadin.firitin.components.datepicker.VDatePicker; -import org.vaadin.firitin.form.BeanValidationForm; - -import java.time.LocalDate; -import java.time.YearMonth; -import java.time.temporal.IsoFields; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import java.util.stream.Collectors; - -@SpringComponent -@PermitAll -@Scope("prototype") -@PageTitle("Horas Trabajadas") -@Route(value = "/hours-worked-list/:hours-workedId?/:action?", layout = MainLayout.class) -public class HoursWorkedView extends BeanValidationForm implements HasUrlParameter { - private final VDatePicker dateField = new VDatePicker("Fecha"); - private final ComboBox teamField = new ComboBox<>("Equipo"); - private ComboBox employeeField; - private final ComboBox tareasEspecificasDropdown = new ComboBox<>("Tarea Específica"); - private final TextField tareaEspecificaInput = new TextField("Otra Tarea Específica"); - private final TextField horasTareaEspecificaField = new TextField("Horas Tarea Específica"); - private final TextField activityField = new TextField("Actividad"); - private final TextField hoursField = new TextField("Horas"); - - private final H2 equipoLabel = new H2("Tareas del Cliente/Equipo"); - private final H2 empresaLabel = new H2("Tareas de la Empresa"); - private final Label totalCompletadoLabel = new Label(); - - private final HoursWorkedService hoursWorkedService; - private final EmployeeService employeeService; - private final TeamService teamService; - private HoursWorked hoursWorked; - private Employee employee; - - private Button saveButton; - - public HoursWorkedView(final HoursWorkedService hoursWorkedService, - final EmployeeService employeeService, - final TeamService teamService) { - super(HoursWorked.class); - this.hoursWorkedService = hoursWorkedService; - this.employeeService = employeeService; - this.teamService = teamService; - - initializeDateField(); - initializeTeamField(); - initializeEmployeeField(); - configureTareasEspecificas(); - - } - - @Override - public void setParameter(final BeforeEvent beforeEvent, final String action) { - final RouteParameters params = beforeEvent.getRouteParameters(); - final String s = params.get("hours-workedId").orElse(null); - - if ("new".equals(action)) { - setEntityWithEnabledSave(new HoursWorked()); - } else { - UUID hoursWorkedId = UUID.fromString(s); - var hoursWorked = hoursWorkedService.getHoursWorked(hoursWorkedId); - setEntityWithEnabledSave(hoursWorked); - - if ("edit".equals(action) && !s.isEmpty()) { - saveButton.setVisible(true); - } else if ("view".equals(action) && !s.isEmpty()) { - saveButton.setVisible(false); - } - } - } - - @Override - protected List getFormComponents() { - return List.of( - dateField, - teamField, - employeeField, - equipoLabel, - activityField, - hoursField, - empresaLabel, - tareasEspecificasDropdown, - tareaEspecificaInput, - horasTareaEspecificaField, - createCloseButton() - ); - } - - private void configureTareasEspecificas() { - tareasEspecificasDropdown.setItems("Entrevistas", "Reuniones", - "Colaboraciones", "Aprendizajes", "Proyectos PFS", - "Consulta Medica", "Afiliación al Seguro", "Fallas Tecnicas", "Otros"); - tareasEspecificasDropdown.setPlaceholder("Selecciona una tarea..."); - - tareasEspecificasDropdown.addValueChangeListener(event -> { - String selected = event.getValue(); - boolean isOtros = "Otros".equals(selected); - tareaEspecificaInput.setVisible(isOtros); - horasTareaEspecificaField.setVisible(true); - if (!isOtros) { - tareaEspecificaInput.clear(); - horasTareaEspecificaField.clear(); - } - }); - tareaEspecificaInput.setVisible(false); - horasTareaEspecificaField.setVisible(false); - } - - protected Button createSaveButton() { - saveButton = new Button("Guardar"); - saveButton.addClickListener(event -> saveHoursWorked()); - return saveButton; - } - - protected Button createCloseButton() { - Button closeButton = new Button("Cancelar"); - closeButton.addClickListener(event -> closeForm()); - return closeButton; - } - - private void initializeTeamField() { - List teams = new ArrayList<>(teamService.findAllTeams()); - teamField.setItems(teamService.findAllTeams()); - teamField.setItemLabelGenerator(Team::getName); - teamField.setValue(null); - teamField.addValueChangeListener(event -> { - Team selectedTeam = event.getValue(); - updateEmployeeField(selectedTeam); - }); - } - - private void updateEmployeeField(final Team selectedTeam) { - if (selectedTeam != null) { - List employeesInTeam = employeeService.findAllEmployees().stream() - .filter(employee -> employee.getTeam() != null && employee.getTeam().equals(selectedTeam)) - .collect(Collectors.toList()); - employeeField.setItems(employeesInTeam); - if (!employeesInTeam.isEmpty()) { - employeeField.setValue(employeesInTeam.get(0)); - } else { - employeeField.clear(); - } - } - } - - private ComboBox initializeEmployeeField() { - employeeField = new ComboBox<>("Empleado"); - List employees = new ArrayList<>(employeeService.findAllEmployees()); - employeeField.setItems(employees); - employeeField.setItemLabelGenerator(this::getEmployeeFullName); - employeeField.setValue(null); - return employeeField; - } - - private String getEmployeeFullName(final Employee employee) { - return "TODOS".equals(employee.getFirstName()) - ? "TODOS" : employee.getFirstName() + " " + employee.getLastName(); - } - - private void initializeDateField() { - LocalDate today = LocalDate.now(); - YearMonth currentMonth = YearMonth.of(today.getYear(), today.getMonth()); - - LocalDate startOfMonth = currentMonth.atDay(1); - - LocalDate maxSelectableDate = today; - - dateField.setMin(startOfMonth); - dateField.setMax(maxSelectableDate); - dateField.setValue(today); - - dateField.addValueChangeListener(event -> { - LocalDate selectedDate = event.getValue(); - if (selectedDate != null) { - int weekNumber = selectedDate.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR); - Notification.show("Número de la semana: " + weekNumber, - 3000, Notification.Position.BOTTOM_CENTER); - if (hoursWorked != null) { - hoursWorked.setWeekNumber(weekNumber); - } - } - }); - } - - private void saveHoursWorked() { - if (isFormValid()) { - HoursWorked hoursWorked = getEntity(); - String actividad = activityField.getValue(); - String tareaEspecifica = tareasEspecificasDropdown.getValue(); - if (actividad != null && !actividad.isEmpty() && tareaEspecifica != null) { - Notification.show("Solo puedes elegir una: actividad del proyecto o tarea de la empresa.", - 3000, Notification.Position.BOTTOM_CENTER); - return; - } - if (actividad != null && !actividad.isEmpty()) { - hoursWorked.setActividad(actividad); - } else if (tareaEspecifica != null) { - if ("Otros".equals(tareaEspecifica)) { - // Validar que se ingresó una tarea específica en el campo de texto - String tareaEspecificaInputValue = tareaEspecificaInput.getValue(); - if (tareaEspecificaInputValue == null || tareaEspecificaInputValue.isEmpty()) { - Notification.show("Por favor, ingresa una tarea específica.", - 3000, Notification.Position.BOTTOM_CENTER); - return; - } - hoursWorked.setTareaEspecifica(tareaEspecificaInputValue); - } else { - hoursWorked.setTareaEspecifica(tareaEspecifica); - } - } else { - Notification.show("Por favor, selecciona una actividad o tarea para guardar.", - 3000, Notification.Position.BOTTOM_CENTER); - return; - } - setFieldValues(hoursWorked); - hoursWorkedService.save(hoursWorked); - Notification.show("Horas trabajadas guardadas correctamente.", - 3000, Notification.Position.BOTTOM_CENTER); - closeForm(); - } - } - - - - private void setFieldValues(final HoursWorked hoursWorked) { - hoursWorked.setDate(dateField.getValue()); - hoursWorked.setTeam(teamField.getValue()); - hoursWorked.setEmployee(employeeField.getValue()); - hoursWorked.setActividad(activityField.getValue()); - try { - double hours = Double.parseDouble(hoursField.getValue()); - hoursWorked.setHours(hours); - } catch (NumberFormatException e) { - Notification.show("Por favor, ingrese un número válido para las horas."); - } - if ("Otros".equals(tareasEspecificasDropdown.getValue())) { - hoursWorked.setActividad(tareaEspecificaInput.getValue()); - try { - double horasEspecifica = Double.parseDouble(horasTareaEspecificaField.getValue()); - hoursWorked.setHours(horasEspecifica); - double totalHoras = hoursWorked.getHours() + horasEspecifica; - hoursWorked.setTotalHours(totalHoras); - } catch (NumberFormatException e) { - Notification.show("Por favor, ingrese un número válido para las horas de la tarea específica."); - } - } - } - - private void closeForm() { - if (hoursWorked != null) { - getUI().ifPresent(ui -> ui.navigate("hours-worked-list/" + hoursWorked.getId().toString())); - } else { - getUI().ifPresent(ui -> ui.navigate("hours-worked-list")); - } - } - - private boolean isFormValid() { - boolean isTareaEspecificaValida = "Otros".equals(tareasEspecificasDropdown.getValue()) - ? !tareaEspecificaInput.isEmpty() - : tareasEspecificasDropdown.getValue() != null; - boolean isActividadValida = !activityField.isEmpty(); - boolean isSoloUnaOpcionElegida = (isActividadValida && tareasEspecificasDropdown.isEmpty()) - || (!isActividadValida && isTareaEspecificaValida); - return dateField.getValue() != null - && teamField.getValue() != null - && employeeField.getValue() != null - && isSoloUnaOpcionElegida; - } - - - private void configureViewOrEditAction(final String action) { - if ("edit".equals(action) && hoursWorked != null) { - setFieldsReadOnly(false); - } else if ("view".equals(action) && hoursWorked != null) { - setFieldsReadOnly(true); - saveButton.setEnabled(false); - } - } - - private void setFieldsReadOnly(final boolean readOnly) { - dateField.setReadOnly(readOnly); - teamField.setReadOnly(readOnly); - employeeField.setReadOnly(readOnly); - activityField.setReadOnly(readOnly); - } -} \ No newline at end of file diff --git a/src/main/java/com/primefactorsolutions/views/MainLayout.java b/src/main/java/com/primefactorsolutions/views/MainLayout.java index 8b23940..07ad80c 100644 --- a/src/main/java/com/primefactorsolutions/views/MainLayout.java +++ b/src/main/java/com/primefactorsolutions/views/MainLayout.java @@ -29,6 +29,8 @@ import org.vaadin.lineawesome.LineAwesomeIcon; import java.util.UUID; +import static com.primefactorsolutions.views.util.AuthUtils.isAdmin; + /** * The main view is a top-level placeholder for other views. */ @@ -125,8 +127,17 @@ public class MainLayout extends AppLayout { private SideNav createNavigation() { final SideNav nav = new SideNav(); + nav.addItem(new SideNavItem("Home", MainView.class, LineAwesomeIcon.HOME_SOLID.create())); + + if (isAdmin(authContext)) { + SideNavItem admin = new SideNavItem("Admin"); + admin.setPrefixComponent(LineAwesomeIcon.BUILDING.create()); + admin.addItem(new SideNavItem("Employees", EmployeesListView.class, + LineAwesomeIcon.USER_EDIT_SOLID.create())); + admin.addItem(new SideNavItem("Documents", DocumentsListView.class, + LineAwesomeIcon.FILE_ALT_SOLID.create())); + nav.addItem(admin); - authContext.getAuthenticatedUser(UserDetails.class).ifPresent(u -> { SideNavItem recruiting = new SideNavItem("Recruiting"); recruiting.setPrefixComponent(LineAwesomeIcon.BUSINESS_TIME_SOLID.create()); recruiting.addItem(new SideNavItem("Assessments", AssessmentsListView.class, @@ -135,39 +146,37 @@ public class MainLayout extends AppLayout { LineAwesomeIcon.USER.create())); recruiting.addItem(new SideNavItem("Questions", QuestionsListView.class, LineAwesomeIcon.QUESTION_SOLID.create())); - - SideNavItem admin = new SideNavItem("Admin"); - admin.setPrefixComponent(LineAwesomeIcon.BUILDING.create()); - admin.addItem(new SideNavItem("Employees", EmployeesListView.class, - LineAwesomeIcon.USER_EDIT_SOLID.create())); - admin.addItem(new SideNavItem("Documents", DocumentsListView.class, - LineAwesomeIcon.FILE_ALT_SOLID.create())); - - SideNavItem timeOff = new SideNavItem("My Time-off", TimeoffView.class, - LineAwesomeIcon.PLANE_DEPARTURE_SOLID.create()); - timeOff.addItem(new SideNavItem("Vacations", RequestsListView.class, - LineAwesomeIcon.UMBRELLA_BEACH_SOLID.create())); - timeOff.addItem(new SideNavItem("Add Vacation", RequestRegisterView.class, - LineAwesomeIcon.CALENDAR_PLUS.create())); - timeOff.addItem(new SideNavItem("Pending Requests", PendingRequestsListView.class, - LineAwesomeIcon.LIST_ALT.create())); - SideNavItem timesheet = new SideNavItem("My Timesheet", TimesheetView.class, - LineAwesomeIcon.HOURGLASS_START_SOLID.create()); - timesheet.addItem(new SideNavItem("Registro de Horas Trabajadas", HoursWorkedListView.class, - LineAwesomeIcon.ID_CARD_SOLID.create())); - timesheet.addItem(new SideNavItem("Reporte Horas Trabajadas", ReporteView.class, - LineAwesomeIcon.ID_CARD_SOLID.create())); - - SideNavItem profile = new SideNavItem("My Profile", ProfileView.class, - LineAwesomeIcon.USER_EDIT_SOLID.create()); - - nav.addItem(new SideNavItem("Home", MainView.class, LineAwesomeIcon.HOME_SOLID.create())); - nav.addItem(admin); nav.addItem(recruiting); - nav.addItem(profile); - nav.addItem(timesheet); - nav.addItem(timeOff); - }); + } + + final SideNavItem timeOff = new SideNavItem("Time-off"); + timeOff.setPrefixComponent(LineAwesomeIcon.PLANE_DEPARTURE_SOLID.create()); + timeOff.addItem(new SideNavItem("Vacations", TimeOffRequestListView.class, + LineAwesomeIcon.UMBRELLA_BEACH_SOLID.create())); + timeOff.addItem(new SideNavItem("Add Vacation", TimeOffNewRequestView.class, + LineAwesomeIcon.CALENDAR_PLUS.create())); + + if (isAdmin(authContext)) { + timeOff.addItem(new SideNavItem("Pending Requests", TimeOffPendingRequestsListView.class, + LineAwesomeIcon.LIST_ALT.create())); + } + + final SideNavItem timesheet = new SideNavItem("Timesheet"); + timesheet.setPrefixComponent(LineAwesomeIcon.HOURGLASS_START_SOLID.create()); + timesheet.addItem(new SideNavItem("Registro de Horas Trabajadas", TimesheetListView.class, + LineAwesomeIcon.ID_CARD_SOLID.create())); + + if (isAdmin(authContext)) { + timesheet.addItem(new SideNavItem("Reporte Horas Trabajadas", TimesheetReportView.class, + LineAwesomeIcon.ID_CARD_SOLID.create())); + } + + final SideNavItem profile = new SideNavItem("Profile", ProfileView.class, + LineAwesomeIcon.USER_EDIT_SOLID.create()); + + nav.addItem(profile); + nav.addItem(timesheet); + nav.addItem(timeOff); return nav; } diff --git a/src/main/java/com/primefactorsolutions/views/QuestionsListView.java b/src/main/java/com/primefactorsolutions/views/QuestionsListView.java index 68b1df2..8eb8fdf 100644 --- a/src/main/java/com/primefactorsolutions/views/QuestionsListView.java +++ b/src/main/java/com/primefactorsolutions/views/QuestionsListView.java @@ -15,6 +15,7 @@ import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; import com.vaadin.flow.shared.Registration; import com.vaadin.flow.spring.annotation.SpringComponent; +import com.vaadin.flow.spring.security.AuthenticationContext; import jakarta.annotation.security.PermitAll; import org.springframework.context.annotation.Scope; import org.vaadin.firitin.components.grid.VGrid; @@ -28,7 +29,8 @@ import java.util.stream.Stream; @PermitAll public class QuestionsListView extends BaseView { - public QuestionsListView(final QuestionService questionService) { + public QuestionsListView(final AuthenticationContext authenticationContext, final QuestionService questionService) { + super(authenticationContext); final HorizontalLayout hl = new HorizontalLayout(); final Button addQuestion = new Button("Add Question"); diff --git a/src/main/java/com/primefactorsolutions/views/SubmissionView.java b/src/main/java/com/primefactorsolutions/views/SubmissionView.java index a48fc98..639b060 100644 --- a/src/main/java/com/primefactorsolutions/views/SubmissionView.java +++ b/src/main/java/com/primefactorsolutions/views/SubmissionView.java @@ -44,7 +44,6 @@ public class SubmissionView extends Main implements HasUrlParameter { private final CompilerService compilerService; private final AssessmentService assessmentService; - private AceEditor questionEditor = null; private AceEditor result = null; private Dialog dialog = null; diff --git a/src/main/java/com/primefactorsolutions/views/RequestRegisterView.java b/src/main/java/com/primefactorsolutions/views/TimeOffNewRequestView.java similarity index 95% rename from src/main/java/com/primefactorsolutions/views/RequestRegisterView.java rename to src/main/java/com/primefactorsolutions/views/TimeOffNewRequestView.java index 4f5ae22..d8537e1 100644 --- a/src/main/java/com/primefactorsolutions/views/RequestRegisterView.java +++ b/src/main/java/com/primefactorsolutions/views/TimeOffNewRequestView.java @@ -30,8 +30,8 @@ import java.util.UUID; @PermitAll @Scope("prototype") @PageTitle("Request") -@Route(value = "/requests/new", layout = MainLayout.class) -public class RequestRegisterView extends VerticalLayout { +@Route(value = "/time-off/requests/new", layout = MainLayout.class) +public class TimeOffNewRequestView extends VerticalLayout { private final ComboBox employeeComboBox = new ComboBox<>("Empleado"); private final ComboBox categoryComboBox = new ComboBox<>("Categoría"); @@ -53,9 +53,9 @@ public class RequestRegisterView extends VerticalLayout { private Button saveButton; private Button closeButton; - public RequestRegisterView(final TimeOffRequestService requestService, - final EmployeeService employeeService, - final VacationService vacationService) { + public TimeOffNewRequestView(final TimeOffRequestService requestService, + final EmployeeService employeeService, + final VacationService vacationService) { this.requestService = requestService; this.employeeService = employeeService; this.vacationService = vacationService; @@ -153,7 +153,6 @@ public class RequestRegisterView extends VerticalLayout { List availableCategories = allCategories.stream() .filter(category -> isCategoryAvailable(employeeRequests, category)) .filter(category -> isCategoryAllowedByGender(category, employee.getGender())) - .filter(category -> category != TimeOffRequestType.TODOS) .filter(category -> shouldIncludeVacationGestionActual(employeeRequests, category)) .filter(category -> shouldIncludeVacationGestionAnterior(employeeRequests, category)) .toList(); @@ -559,6 +558,6 @@ public class RequestRegisterView extends VerticalLayout { } private void closeForm() { - getUI().ifPresent(ui -> ui.navigate(RequestsListView.class)); + getUI().ifPresent(ui -> ui.navigate(TimeOffRequestListView.class)); } } diff --git a/src/main/java/com/primefactorsolutions/views/PendingRequestsListView.java b/src/main/java/com/primefactorsolutions/views/TimeOffPendingRequestsListView.java similarity index 84% rename from src/main/java/com/primefactorsolutions/views/PendingRequestsListView.java rename to src/main/java/com/primefactorsolutions/views/TimeOffPendingRequestsListView.java index abb096a..a1e96ba 100644 --- a/src/main/java/com/primefactorsolutions/views/PendingRequestsListView.java +++ b/src/main/java/com/primefactorsolutions/views/TimeOffPendingRequestsListView.java @@ -22,6 +22,7 @@ import com.vaadin.flow.router.Route; import com.vaadin.flow.server.StreamRegistration; import com.vaadin.flow.server.StreamResource; import com.vaadin.flow.spring.annotation.SpringComponent; +import com.vaadin.flow.spring.security.AuthenticationContext; import jakarta.annotation.security.PermitAll; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; @@ -44,22 +45,23 @@ import static com.primefactorsolutions.views.Constants.PAGE_SIZE; @SpringComponent @Scope("prototype") @PageTitle("Pending Requests") -@Route(value = "/pending-requests", layout = MainLayout.class) +@Route(value = "/time-off/requests/pending", layout = MainLayout.class) @PermitAll -public class PendingRequestsListView extends BaseView { +public class TimeOffPendingRequestsListView extends BaseView { private final TimeOffRequestService requestService; private final EmployeeService employeeService; private final TeamService teamService; private final PagingGrid pendingRequestsGrid = new PagingGrid<>(); - private ComboBox employeeFilter; private ComboBox teamFilter; private ComboBox categoryFilter; - public PendingRequestsListView(final TimeOffRequestService requestService, - final EmployeeService employeeService, - final TeamService teamService) { + public TimeOffPendingRequestsListView(final AuthenticationContext authenticationContext, + final TimeOffRequestService requestService, + final EmployeeService employeeService, + final TeamService teamService) { + super(authenticationContext); this.requestService = requestService; this.employeeService = employeeService; this.teamService = teamService; @@ -91,13 +93,11 @@ public class PendingRequestsListView extends BaseView { final MenuBar menuBar = new MenuBar(); menuBar.addThemeVariants(MenuBarVariant.LUMO_TERTIARY_INLINE); final MenuItem approveItem = MenuBarUtils.createIconItem(menuBar, VaadinIcon.CHECK, "Aprobar"); - approveItem.addClickListener((ComponentEventListener>) menuItemClickEvent -> { - actionForRequest(timeOffRequest.getId(), TimeOffRequestStatus.APROBADO); - }); + approveItem.addClickListener((ComponentEventListener>) menuItemClickEvent -> + actionForRequest(timeOffRequest.getId(), TimeOffRequestStatus.APROBADO)); final MenuItem rejectItem = MenuBarUtils.createIconItem(menuBar, VaadinIcon.BAN, "Rechazar"); - rejectItem.addClickListener((ComponentEventListener>) menuItemClickEvent -> { - actionForRequest(timeOffRequest.getId(), TimeOffRequestStatus.RECHAZADO); - }); + rejectItem.addClickListener((ComponentEventListener>) menuItemClickEvent -> + actionForRequest(timeOffRequest.getId(), TimeOffRequestStatus.RECHAZADO)); return menuBar; }); @@ -132,20 +132,20 @@ public class PendingRequestsListView extends BaseView { List filteredPendingRequests = requestService.findRequestsByState(TimeOffRequestStatus.SOLICITADO); - if (employee != null && !"TODOS".equals(employee.getFirstName())) { + if (employee != null) { filteredPendingRequests = filteredPendingRequests.stream() .filter(emp -> emp.getEmployee().getId().equals(employee.getId())) .collect(Collectors.toList()); } - if (team != null && !"TODOS".equals(team.getName())) { + if (team != null) { filteredPendingRequests = filteredPendingRequests.stream() .filter(emp -> emp.getEmployee().getTeam() != null && emp.getEmployee().getTeam().getId().equals(team.getId())) .collect(Collectors.toList()); } - if (category != null && category != TimeOffRequestType.TODOS) { + if (category != null) { filteredPendingRequests = filteredPendingRequests.stream() .filter(emp -> emp.getCategory().equals(category)) .collect(Collectors.toList()); @@ -180,11 +180,12 @@ public class PendingRequestsListView extends BaseView { private ComboBox createEmployeeFilter() { employeeFilter = new ComboBox<>("Empleado"); - List employees = new ArrayList<>(employeeService.findAllEmployees()); - employees.addFirst(createAllEmployeesOption()); + employeeFilter.setClearButtonVisible(true); + employeeFilter.setPlaceholder("TODOS"); + final List employees = new ArrayList<>(employeeService.findAllEmployees()); + employeeFilter.setItems(employees); employeeFilter.setItemLabelGenerator(this::getEmployeeFullNameLabel); - employeeFilter.setValue(employees.getFirst()); employeeFilter.addValueChangeListener(event -> refreshGeneralPendingRequestsGrid( event.getValue(), @@ -197,11 +198,11 @@ public class PendingRequestsListView extends BaseView { private ComboBox createTeamFilter() { teamFilter = new ComboBox<>("Equipo"); - List teams = new ArrayList<>(teamService.findAllTeams()); - teams.addFirst(createAllTeamsOption()); + teamFilter.setClearButtonVisible(true); + teamFilter.setPlaceholder("TODOS"); + final List teams = new ArrayList<>(teamService.findAllTeams()); teamFilter.setItems(teams); teamFilter.setItemLabelGenerator(this::getTeamLabel); - teamFilter.setValue(teams.getFirst()); teamFilter.addValueChangeListener(event -> refreshGeneralPendingRequestsGrid( employeeFilter.getValue(), @@ -214,8 +215,9 @@ public class PendingRequestsListView extends BaseView { private ComboBox createCategoryFilter() { categoryFilter = new ComboBox<>("Categoría"); + categoryFilter.setPlaceholder("TODOS"); + categoryFilter.setClearButtonVisible(true); categoryFilter.setItems(TimeOffRequestType.values()); - categoryFilter.setValue(TimeOffRequestType.values()[0]); categoryFilter.addValueChangeListener(event -> refreshGeneralPendingRequestsGrid( employeeFilter.getValue(), @@ -226,18 +228,6 @@ public class PendingRequestsListView extends BaseView { return categoryFilter; } - private Employee createAllEmployeesOption() { - Employee allEmployeesOption = new Employee(); - allEmployeesOption.setFirstName("TODOS"); - return allEmployeesOption; - } - - private Team createAllTeamsOption() { - Team allTeamsOption = new Team(); - allTeamsOption.setName("TODOS"); - return allTeamsOption; - } - private void downloadReport() { StreamResource resource = generateGeneralVacationReport(); getUI().ifPresent(ui -> openDocumentStream(resource, ui)); diff --git a/src/main/java/com/primefactorsolutions/views/RequestsListView.java b/src/main/java/com/primefactorsolutions/views/TimeOffRequestListView.java similarity index 90% rename from src/main/java/com/primefactorsolutions/views/RequestsListView.java rename to src/main/java/com/primefactorsolutions/views/TimeOffRequestListView.java index 24bd3e0..dde3426 100644 --- a/src/main/java/com/primefactorsolutions/views/RequestsListView.java +++ b/src/main/java/com/primefactorsolutions/views/TimeOffRequestListView.java @@ -22,6 +22,7 @@ import com.vaadin.flow.router.Route; import com.vaadin.flow.server.StreamRegistration; import com.vaadin.flow.server.StreamResource; import com.vaadin.flow.spring.annotation.SpringComponent; +import com.vaadin.flow.spring.security.AuthenticationContext; import jakarta.annotation.security.PermitAll; import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; @@ -43,25 +44,27 @@ import static com.primefactorsolutions.views.util.MenuBarUtils.createIconItem; @SpringComponent @Scope("prototype") @PageTitle("Requests") -@Route(value = "/requests", layout = MainLayout.class) +@Route(value = "/time-off/requests", layout = MainLayout.class) @PermitAll -public class RequestsListView extends BaseView { +public class TimeOffRequestListView extends BaseView { private final TimeOffRequestService requestService; private final EmployeeService employeeService; private final TeamService teamService; private final VacationService vacationService; private final PagingGrid requestGrid = new PagingGrid<>(); - private ComboBox employeeFilter; private ComboBox teamFilter; private ComboBox categoryFilter; private ComboBox stateFilter; - public RequestsListView(final TimeOffRequestService requestService, - final EmployeeService employeeService, - final TeamService teamService, - final VacationService vacationService) { + public TimeOffRequestListView( + final AuthenticationContext authenticationContext, + final TimeOffRequestService requestService, + final EmployeeService employeeService, + final TeamService teamService, + final VacationService vacationService) { + super(authenticationContext); this.requestService = requestService; this.employeeService = employeeService; this.teamService = teamService; @@ -72,8 +75,12 @@ public class RequestsListView extends BaseView { private void initializeView() { requestService.updateRequestStatuses(); - Button downloadButton = new Button("Descargar reporte", event -> downloadReport()); - getCurrentPageLayout().add(downloadButton); + + if (isRoleAdmin()) { + final Button downloadButton = new Button("Descargar reporte", event -> downloadReport()); + getCurrentPageLayout().add(downloadButton); + } + setupFilters(); setupRequestGrid(); getCurrentPageLayout().add(requestGrid); @@ -127,19 +134,19 @@ public class RequestsListView extends BaseView { final Status state) { List filteredEmployees = employeeService.findAllEmployees(); - if (employee != null && !"TODOS".equals(employee.getFirstName())) { + if (employee != null) { filteredEmployees = filteredEmployees.stream() .filter(emp -> emp.getId().equals(employee.getId())) .collect(Collectors.toList()); } - if (team != null && !"TODOS".equals(team.getName())) { + if (team != null) { filteredEmployees = filteredEmployees.stream() .filter(emp -> emp.getTeam() != null && emp.getTeam().getId().equals(team.getId())) .collect(Collectors.toList()); } - if (category != null && category != TimeOffRequestType.values()[0]) { + if (category != null) { filteredEmployees = filteredEmployees.stream() .filter(emp -> { Optional request = requestService @@ -149,7 +156,7 @@ public class RequestsListView extends BaseView { .collect(Collectors.toList()); } - if (state != null && state != Status.TODOS) { + if (state != null) { filteredEmployees = filteredEmployees.stream() .filter(emp -> { Optional request = requestService @@ -164,8 +171,7 @@ public class RequestsListView extends BaseView { } private String getEmployeeFullName(final Employee employee) { - return "TODOS".equals(employee.getFirstName()) - ? "TODOS" : employee.getFirstName() + " " + employee.getLastName(); + return employee.getFirstName() + " " + employee.getLastName(); } private String getTeamName(final Employee employee) { @@ -174,7 +180,7 @@ public class RequestsListView extends BaseView { } private String getTeamLabel(final Team team) { - return "TODOS".equals(team.getName()) ? "TODOS" : team.getName(); + return team.getName(); } private String getEmployeeStatus(final Employee employee) { @@ -375,11 +381,12 @@ public class RequestsListView extends BaseView { private ComboBox createEmployeeFilter() { employeeFilter = new ComboBox<>("Empleado"); - List employees = new ArrayList<>(employeeService.findAllEmployees()); - employees.addFirst(createAllEmployeesOption()); + + final List employees = new ArrayList<>(employeeService.findAllEmployees()); + employeeFilter.setPlaceholder("TODOS"); + employeeFilter.setClearButtonVisible(true); employeeFilter.setItems(employees); employeeFilter.setItemLabelGenerator(this::getEmployeeFullName); - employeeFilter.setValue(employees.getFirst()); employeeFilter.addValueChangeListener(event -> refreshGeneralRequestGrid( event.getValue(), @@ -388,16 +395,17 @@ public class RequestsListView extends BaseView { stateFilter.getValue() ) ); + return employeeFilter; } private ComboBox createTeamFilter() { teamFilter = new ComboBox<>("Equipo"); - List teams = new ArrayList<>(teamService.findAllTeams()); - teams.addFirst(createAllTeamsOption()); + teamFilter.setPlaceholder("TODOS"); + teamFilter.setClearButtonVisible(true); + final List teams = new ArrayList<>(teamService.findAllTeams()); teamFilter.setItems(teams); teamFilter.setItemLabelGenerator(this::getTeamLabel); - teamFilter.setValue(teams.getFirst()); teamFilter.addValueChangeListener(event -> refreshGeneralRequestGrid( employeeFilter.getValue(), @@ -411,8 +419,9 @@ public class RequestsListView extends BaseView { private ComboBox createCategoryFilter() { categoryFilter = new ComboBox<>("Category"); + categoryFilter.setClearButtonVisible(true); + categoryFilter.setPlaceholder("TODOS"); categoryFilter.setItems(TimeOffRequestType.values()); - categoryFilter.setValue(TimeOffRequestType.values()[0]); categoryFilter.addValueChangeListener(event -> refreshGeneralRequestGrid( employeeFilter.getValue(), @@ -426,8 +435,9 @@ public class RequestsListView extends BaseView { private ComboBox createStateFilter() { stateFilter = new ComboBox<>("Estado del empleado"); + stateFilter.setPlaceholder("TODOS"); + stateFilter.setClearButtonVisible(true); stateFilter.setItems(Status.values()); - stateFilter.setValue(Status.values()[0]); stateFilter.addValueChangeListener(event -> refreshGeneralRequestGrid( employeeFilter.getValue(), @@ -440,29 +450,12 @@ public class RequestsListView extends BaseView { } private enum Status { - TODOS, EN_DESCANSO, EN_FUNCIONES } - private Employee createAllEmployeesOption() { - Employee allEmployeesOption = new Employee(); - allEmployeesOption.setFirstName("TODOS"); - return allEmployeesOption; - } - - private Team createAllTeamsOption() { - Team allTeamsOption = new Team(); - allTeamsOption.setName("TODOS"); - return allTeamsOption; - } - - private void navigateToMainView() { - getUI().ifPresent(ui -> ui.navigate(MainView.class)); - } - private void navigateToTimeOffRequestView(final UUID idEmployee) { - getUI().ifPresent(ui -> ui.navigate("requests/" + idEmployee.toString())); + getUI().ifPresent(ui -> ui.navigate(TimeOffRequestsByEmployeeView.class, idEmployee.toString())); } private ByteArrayInputStream generateExcelReport(final List employees) { diff --git a/src/main/java/com/primefactorsolutions/views/RequestView.java b/src/main/java/com/primefactorsolutions/views/TimeOffRequestView.java similarity index 90% rename from src/main/java/com/primefactorsolutions/views/RequestView.java rename to src/main/java/com/primefactorsolutions/views/TimeOffRequestView.java index 47b5ae2..571d1b4 100644 --- a/src/main/java/com/primefactorsolutions/views/RequestView.java +++ b/src/main/java/com/primefactorsolutions/views/TimeOffRequestView.java @@ -25,7 +25,7 @@ import java.util.UUID; @Scope("prototype") @PageTitle("Request") @Route(value = "/requests/:requestId?/:action?", layout = MainLayout.class) -public class RequestView extends BeanValidationForm implements HasUrlParameter { +public class TimeOffRequestView extends BeanValidationForm implements HasUrlParameter { private final ComboBox state = new ComboBox<>("Estado de la solicitud"); private final DatePicker expiration = new DatePicker("Vencimiento"); @@ -41,9 +41,9 @@ public class RequestView extends BeanValidationForm implements H private Button saveButton; - public RequestView(final TimeOffRequestService requestService, - final EmployeeService employeeService, - final TeamService teamService) { + public TimeOffRequestView(final TimeOffRequestService requestService, + final EmployeeService employeeService, + final TeamService teamService) { super(TimeOffRequest.class); this.requestService = requestService; this.employeeService = employeeService; @@ -125,7 +125,7 @@ public class RequestView extends BeanValidationForm implements H } private void closeForm() { - getUI().ifPresent(ui -> ui.navigate("requests/" + employee.getId().toString())); + getUI().ifPresent(ui -> ui.navigate(TimeOffRequestsByEmployeeView.class, employee.getId().toString())); } private boolean isFormValid() { diff --git a/src/main/java/com/primefactorsolutions/views/RequestEmployeeView.java b/src/main/java/com/primefactorsolutions/views/TimeOffRequestsByEmployeeView.java similarity index 95% rename from src/main/java/com/primefactorsolutions/views/RequestEmployeeView.java rename to src/main/java/com/primefactorsolutions/views/TimeOffRequestsByEmployeeView.java index b0a5d07..f6c21b2 100644 --- a/src/main/java/com/primefactorsolutions/views/RequestEmployeeView.java +++ b/src/main/java/com/primefactorsolutions/views/TimeOffRequestsByEmployeeView.java @@ -26,6 +26,7 @@ import com.vaadin.flow.router.Route; import com.vaadin.flow.server.StreamRegistration; import com.vaadin.flow.server.StreamResource; import com.vaadin.flow.spring.annotation.SpringComponent; +import com.vaadin.flow.spring.security.AuthenticationContext; import jakarta.annotation.security.PermitAll; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; @@ -51,8 +52,8 @@ import static com.primefactorsolutions.views.util.MenuBarUtils.createIconItem; @PermitAll @Scope("prototype") @PageTitle("Employee Request") -@Route(value = "/requests", layout = MainLayout.class) -public class RequestEmployeeView extends BaseView implements HasUrlParameter { +@Route(value = "/time-off/requests", layout = MainLayout.class) +public class TimeOffRequestsByEmployeeView extends BaseView implements HasUrlParameter { private final TimeOffRequestService requestService; private final EmployeeService employeeService; @@ -66,10 +67,11 @@ public class RequestEmployeeView extends BaseView implements HasUrlParameter ui.navigate(RequestView.class, request.getId().toString() + "/" + action)); + getUI().ifPresent(ui -> ui.navigate(TimeOffRequestView.class, request.getId().toString() + "/" + action)); } private void refreshRequestGrid(final TimeOffRequestType category, final TimeOffRequestStatus state) { @@ -435,8 +437,7 @@ public class RequestEmployeeView extends BaseView implements HasUrlParameter employeeFilter; private ComboBox teamFilter; - public HoursWorkedListView(final HoursWorkedService hoursWorkedService, - final EmployeeService employeeService, - final TeamService teamService) { + public TimesheetListView(final AuthenticationContext authenticationContext, + final HoursWorkedService hoursWorkedService, + final EmployeeService employeeService, + final TeamService teamService) { + super(authenticationContext); this.hoursWorkedService = hoursWorkedService; this.employeeService = employeeService; this.teamService = teamService; @@ -65,7 +66,7 @@ public class HoursWorkedListView extends BaseView { List hoursWorkedList = fetchFilteredHoursWorked(start, pageSize, employee, team); double totalHours = hoursWorkedList.stream() - .mapToDouble(HoursWorked::getTotalHours) + .mapToDouble(HoursWorked::getHours) .sum(); Notification.show("Total de horas trabajadas: " + totalHours, @@ -82,37 +83,21 @@ public class HoursWorkedListView extends BaseView { final Team team) { List filteredHoursWorked = hoursWorkedService.findAll(); - if (employee != null && !"TODOS".equals(employee.getFirstName())) { + if (employee != null) { filteredHoursWorked = filteredHoursWorked.stream() .filter(hw -> hw.getEmployee().getId().equals(employee.getId())) .collect(Collectors.toList()); } - if (team != null && !"TODOS".equals(team.getName())) { + if (team != null) { filteredHoursWorked = filteredHoursWorked.stream() .filter(hw -> hw.getEmployee().getTeam() != null && hw.getEmployee().getTeam().getId().equals(team.getId())) .collect(Collectors.toList()); } - for (HoursWorked hoursWorked : filteredHoursWorked) { - if (employee != null && hoursWorked.getEmployee().getId().equals(employee.getId())) { - LocalDate date = hoursWorked.getDate(); - int currentWeek = date.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR); - - double totalWorkedInSameWeek = filteredHoursWorked.stream() - .filter(hw -> hw.getEmployee().getId().equals(employee.getId()) - && - hw.getDate().get(IsoFields.WEEK_OF_WEEK_BASED_YEAR) == currentWeek) - .mapToDouble(HoursWorked::getHours) - .sum(); - - double updatedPendingHours = totalWorkedInSameWeek - hoursWorked.getHours(); - hoursWorked.setHoraspendientes(updatedPendingHours); - } - } - int end = Math.min(start + pageSize, filteredHoursWorked.size()); + return filteredHoursWorked.subList(start, end); } @@ -144,26 +129,26 @@ public class HoursWorkedListView extends BaseView { .getName() : "Sin asignar") .setHeader("Equipo"); hoursWorkedGrid.addColumn(hw -> { - String actividad = hw.getActividad() != null ? hw.getActividad() : "Sin Actividad"; - String tareaEspecifica = hw.getTareaEspecifica() != null ? hw.getTareaEspecifica() : ""; + String actividad = hw.getActivity() != null ? hw.getActivity() : "Sin Actividad"; + String tareaEspecifica = hw.getTask() != null ? hw.getTask() : ""; return !tareaEspecifica.isEmpty() ? tareaEspecifica : actividad; }).setHeader("Actividad"); hoursWorkedGrid.addColumn(hw -> { - if (hw.getTareaEspecifica() != null && !hw.getTareaEspecifica().isEmpty()) { - return calcularHorasPorTareaEspecifica(hw); + if (hw.getTask() != null && !hw.getTask().isEmpty()) { + return calculateHoursPerTask(hw); } else { - return calcularHorasPorActividadGeneral(hw); + return 0.0; } }).setHeader("Total Horas").setSortable(true); - hoursWorkedGrid.addColumn(hw -> hw.getHoraspendientes() - calcularTotal(hw)).setHeader("Horas Pendientes") + hoursWorkedGrid.addColumn(hw -> 40 - calculateTotal(hw)).setHeader("Horas Pendientes") .setSortable(true); hoursWorkedGrid.addComponentColumn((ValueProvider) hoursWorked -> { final MenuBar menuBar = new MenuBar(); menuBar.addThemeVariants(MenuBarVariant.LUMO_TERTIARY_INLINE); final MenuItem viewItem = MenuBarUtils.createIconItem(menuBar, VaadinIcon.EYE, "Ver"); viewItem.addClickListener((ComponentEventListener>) menuItemClickEvent -> { - navigateToHoursWorkedView(hoursWorked.getEmployee().getId()); + navigateToHoursWorkedView(hoursWorked.getId()); }); return menuBar; }); @@ -172,33 +157,23 @@ public class HoursWorkedListView extends BaseView { hoursWorkedGrid.setPageSize(PAGE_SIZE); } - private double calcularHorasPorTareaEspecifica(final HoursWorked hoursWorked) { - List tareas = hoursWorkedService.findListHoursWorkedEmployee( + private double calculateHoursPerTask(final HoursWorked hoursWorked) { + final List tasks = hoursWorkedService.findListHoursWorkedEmployee( hoursWorked.getEmployee().getId(), hoursWorked.getWeekNumber()); - return tareas.stream() - .filter(hw -> Objects.equals(hw.getTareaEspecifica(), hoursWorked.getTareaEspecifica())) + return tasks.stream() + .filter(hw -> Objects.equals(hw.getTask(), hoursWorked.getTask())) .mapToDouble(HoursWorked::getHours) .sum(); } - private double calcularHorasPorActividadGeneral(final HoursWorked hoursWorked) { - List actividades = hoursWorkedService.findListHoursWorkedEmployee( - hoursWorked.getEmployee().getId(), hoursWorked.getWeekNumber()); - return actividades.stream() - .filter(hw -> Objects.equals(hw.getActividad(), hoursWorked.getActividad()) - && (hw.getTareaEspecifica() == null || hw.getTareaEspecifica().isEmpty())) - .mapToDouble(HoursWorked::getHours) - .sum(); + private void navigateToHoursWorkedView(final UUID idRecord) { + getUI().ifPresent(ui -> ui.navigate(TimesheetRecordView.class, idRecord.toString() + "/view")); } - private void navigateToHoursWorkedView(final UUID idEmployee) { - getUI().ifPresent(ui -> ui.navigate("hours-worked-list/" + idEmployee.toString())); - } - - private double calcularTotal(final HoursWorked hoursWorked) { - List listHoursworkedemploye = hoursWorkedService.findListHoursWorkedEmployee( + private double calculateTotal(final HoursWorked hoursWorked) { + final List listHoursworkedEmployee = hoursWorkedService.findListHoursWorkedEmployee( hoursWorked.getEmployee().getId(), hoursWorked.getWeekNumber()); - return calculateTotalUtilized(listHoursworkedemploye); + return calculateTotalUtilized(listHoursworkedEmployee); } private double calculateTotalUtilized(final List employeeRequests) { @@ -220,16 +195,16 @@ public class HoursWorkedListView extends BaseView { } private void navigateToHours() { - getUI().ifPresent(ui -> ui.navigate(HoursWorkedView.class, "new")); + getUI().ifPresent(ui -> ui.navigate(TimesheetRecordView.class, "new")); } private ComboBox createEmployeeFilter() { employeeFilter = new ComboBox<>("Empleado"); + employeeFilter.setPlaceholder("TODOS"); + employeeFilter.setClearButtonVisible(true); final List employees = new ArrayList<>(employeeService.findAllEmployees()); - employees.addFirst(createAllEmployeesOption()); employeeFilter.setItems(employees); employeeFilter.setItemLabelGenerator(this::getEmployeeFullName); - employeeFilter.setValue(employees.getFirst()); employeeFilter.addValueChangeListener(event -> refreshGridListHoursWorked( event.getValue(), @@ -247,11 +222,11 @@ public class HoursWorkedListView extends BaseView { private ComboBox createTeamFilter() { teamFilter = new ComboBox<>("Equipo"); - List teams = new ArrayList<>(teamService.findAllTeams()); - teams.addFirst(createAllTeamsOption()); + final List teams = new ArrayList<>(teamService.findAllTeams()); + teamFilter.setPlaceholder("TODOS"); + teamFilter.setClearButtonVisible(true); teamFilter.setItems(teams); teamFilter.setItemLabelGenerator(this::getTeamLabel); - teamFilter.setValue(teams.getFirst()); teamFilter.addValueChangeListener(event -> refreshGridListHoursWorked( employeeFilter.getValue(), @@ -264,16 +239,4 @@ public class HoursWorkedListView extends BaseView { private String getTeamLabel(final Team team) { return team != null && !"TODOS".equals(team.getName()) ? team.getName() : "TODOS"; } - - private Employee createAllEmployeesOption() { - Employee allEmployeesOption = new Employee(); - allEmployeesOption.setFirstName("TODOS"); - return allEmployeesOption; - } - - private Team createAllTeamsOption() { - Team allTeamsOption = new Team(); - allTeamsOption.setName("TODOS"); - return allTeamsOption; - } } diff --git a/src/main/java/com/primefactorsolutions/views/TimesheetRecordView.java b/src/main/java/com/primefactorsolutions/views/TimesheetRecordView.java new file mode 100644 index 0000000..6b17a4e --- /dev/null +++ b/src/main/java/com/primefactorsolutions/views/TimesheetRecordView.java @@ -0,0 +1,222 @@ +package com.primefactorsolutions.views; + +import com.primefactorsolutions.model.Employee; +import com.primefactorsolutions.model.HoursWorked; +import com.primefactorsolutions.model.Team; +import com.primefactorsolutions.service.EmployeeService; +import com.primefactorsolutions.service.HoursWorkedService; +import com.primefactorsolutions.service.TeamService; +import com.vaadin.flow.component.Component; +import com.vaadin.flow.component.notification.Notification; +import com.vaadin.flow.component.textfield.NumberField; +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.router.*; +import com.vaadin.flow.spring.annotation.SpringComponent; +import jakarta.annotation.security.PermitAll; +import org.springframework.context.annotation.Scope; +import org.vaadin.firitin.components.datepicker.VDatePicker; +import org.vaadin.firitin.form.BeanValidationForm; + +import java.time.LocalDate; +import java.time.YearMonth; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +@SuppressWarnings("deprecation") +@SpringComponent +@PermitAll +@Scope("prototype") +@PageTitle("Horas Trabajadas") +@Route(value = "/timesheet/:hours-workedId?/:action?", layout = MainLayout.class) +public class TimesheetRecordView extends BeanValidationForm implements HasUrlParameter { + private final ComboBox team = new ComboBox<>("Equipo"); + private ComboBox employee; + + private final ComboBox task = new ComboBox<>("Tarea Específica"); + private final TextField activity = new TextField("Actividad"); + private final VDatePicker date = new VDatePicker("Fecha"); + private final NumberField hours = new NumberField("Horas Tarea Específica"); + private Button saveButton; + + private final HoursWorkedService hoursWorkedService; + private final EmployeeService employeeService; + private final TeamService teamService; + + private HoursWorked hoursWorked; + + public TimesheetRecordView(final HoursWorkedService hoursWorkedService, + final EmployeeService employeeService, + final TeamService teamService) { + super(HoursWorked.class); + this.hoursWorkedService = hoursWorkedService; + this.employeeService = employeeService; + this.teamService = teamService; + + initializeDateField(); + initializeTeamField(); + initializeEmployeeField(); + configureTasks(); + } + + @Override + public void setParameter(final BeforeEvent beforeEvent, final String action) { + final RouteParameters params = beforeEvent.getRouteParameters(); + final String s = params.get("hours-workedId").orElse(null); + + if ("new".equals(action) || s == null) { + setEntityWithEnabledSave(new HoursWorked()); + } else { + final UUID hoursWorkedId = UUID.fromString(s); + hoursWorked = hoursWorkedService.getHoursWorked(hoursWorkedId); + setEntityWithEnabledSave(hoursWorked); + + if ("edit".equals(action) && !s.isEmpty()) { + saveButton.setVisible(true); + } else if ("view".equals(action) && !s.isEmpty()) { + saveButton.setVisible(false); + } + } + } + + @Override + protected List getFormComponents() { + return List.of( + date, + team, + employee, + activity, + task, + hours, + createCloseButton() + ); + } + + private void configureTasks() { + task.setItems( + "Entrevistas", + "Reuniones", + "Colaboraciones", + "Aprendizajes", + "Proyectos PFS", + "Consulta Medica", + "Afiliación al Seguro", + "Fallas Tecnicas", + "Otros"); + task.setPlaceholder("Selecciona una tarea..."); + } + + protected Button createSaveButton() { + saveButton = new Button("Guardar"); + saveButton.addClickListener(event -> saveHoursWorked()); + return saveButton; + } + + protected Button createCloseButton() { + final Button closeButton = new Button("Cancelar"); + closeButton.addClickListener(event -> closeForm()); + return closeButton; + } + + private void initializeTeamField() { + team.setItems(teamService.findAllTeams()); + team.setItemLabelGenerator(Team::getName); + team.setValue(null); + team.addValueChangeListener(event -> { + Team selectedTeam = event.getValue(); + updateEmployeeField(selectedTeam); + }); + } + + private void updateEmployeeField(final Team selectedTeam) { + if (selectedTeam != null) { + List employeesInTeam = employeeService.findAllEmployees().stream() + .filter(employee -> employee.getTeam() != null && employee.getTeam().equals(selectedTeam)) + .collect(Collectors.toList()); + employee.setItems(employeesInTeam); + if (!employeesInTeam.isEmpty()) { + employee.setValue(employeesInTeam.getFirst()); + } else { + employee.clear(); + } + } + } + + private void initializeEmployeeField() { + employee = new ComboBox<>("Empleado"); + List employees = new ArrayList<>(employeeService.findAllEmployees()); + employee.setItems(employees); + employee.setItemLabelGenerator(this::getEmployeeFullName); + employee.setValue(null); + } + + private String getEmployeeFullName(final Employee employee) { + return "TODOS".equals(employee.getFirstName()) + ? "TODOS" : employee.getFirstName() + " " + employee.getLastName(); + } + + private void initializeDateField() { + final LocalDate today = LocalDate.now(); + final YearMonth currentMonth = YearMonth.of(today.getYear(), today.getMonth()); + final LocalDate startOfMonth = currentMonth.atDay(1); + + date.setMin(startOfMonth); + date.setMax(today); + date.setValue(today); + } + + private void saveHoursWorked() { + if (isFormValid()) { + HoursWorked hoursWorked = getEntity(); + String actividad = this.activity.getValue(); + String tareaEspecifica = task.getValue(); + + if (actividad != null && !actividad.isEmpty() && tareaEspecifica != null) { + Notification.show("Solo puedes elegir una: actividad del proyecto o tarea de la empresa.", + 3000, Notification.Position.BOTTOM_CENTER); + return; + } + + if (actividad != null && !actividad.isEmpty()) { + hoursWorked.setActivity(actividad); + } else if (tareaEspecifica != null) { + hoursWorked.setTask(tareaEspecifica); + } else { + Notification.show("Por favor, selecciona una actividad o tarea para guardar.", + 3000, Notification.Position.BOTTOM_CENTER); + return; + } + + setFieldValues(hoursWorked); + hoursWorkedService.save(hoursWorked); + closeForm(); + } + } + + private void setFieldValues(final HoursWorked hoursWorked) { + hoursWorked.setDate(date.getValue()); + hoursWorked.setTeam(team.getValue()); + hoursWorked.setEmployee(employee.getValue()); + hoursWorked.setActivity(activity.getValue()); + hoursWorked.setHours(hours.getValue()); + } + + private void closeForm() { + if (hoursWorked != null) { + getUI().ifPresent(ui -> ui.navigate(TimesheetRecordView.class, + hoursWorked.getEmployee().getId().toString() + "/view")); + } else { + getUI().ifPresent(ui -> ui.navigate(TimesheetListView.class)); + } + } + + private boolean isFormValid() { + return date.getValue() != null + && team.getValue() != null + && employee.getValue() != null + && task.getValue() != null; + } +} \ No newline at end of file diff --git a/src/main/java/com/primefactorsolutions/views/ReporteView.java b/src/main/java/com/primefactorsolutions/views/TimesheetReportView.java similarity index 82% rename from src/main/java/com/primefactorsolutions/views/ReporteView.java rename to src/main/java/com/primefactorsolutions/views/TimesheetReportView.java index a31f148..bdb3684 100644 --- a/src/main/java/com/primefactorsolutions/views/ReporteView.java +++ b/src/main/java/com/primefactorsolutions/views/TimesheetReportView.java @@ -17,7 +17,8 @@ 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 com.vaadin.flow.spring.security.AuthenticationContext; +import jakarta.annotation.security.RolesAllowed; import org.springframework.beans.factory.annotation.Autowired; import com.primefactorsolutions.service.EmployeeService; @@ -32,31 +33,30 @@ import java.util.Locale; import java.util.Map; import java.util.stream.Collectors; -@PermitAll -@Route(value = "/reportes", layout = MainLayout.class) +@Route(value = "/timesheet/report", layout = MainLayout.class) @PageTitle("Reporte de Horas Trabajadas") -public class ReporteView extends BaseView { +@RolesAllowed("ROLE_ADMIN") +public class TimesheetReportView extends BaseView { 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 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 final int currentYear = LocalDate.now().getYear(); @Autowired - public ReporteView(final HoursWorkedService hoursWorkedService, - final ReportService reportService, final TeamService teamService, - final EmployeeService employeeService) { + public TimesheetReportView(final AuthenticationContext authenticationContext, + final HoursWorkedService hoursWorkedService, + final ReportService reportService, + final TeamService teamService, + final EmployeeService employeeService) { + super(authenticationContext); this.hoursWorkedService = hoursWorkedService; this.reportService = reportService; this.teamService = teamService; @@ -65,7 +65,7 @@ public class ReporteView extends BaseView { H2 title = new H2("Reporte de Horas Trabajadas"); getCurrentPageLayout().add(title); - List teams = teamService.findAllTeams(); + final List teams = teamService.findAllTeams(); equipoComboBox.setItems(teams); equipoComboBox.setItemLabelGenerator(Team::getName); @@ -78,11 +78,11 @@ public class ReporteView extends BaseView { semanaInfoSpan.setText(selectedWeek != null ? selectedWeek : "Selecciona una semana"); }); - Button reportButton = new Button("Generar Reporte de Horas Trabajadas", + final Button reportButton = new Button("Generar Reporte de Horas Trabajadas", event -> generateHoursWorkedReport()); getCurrentPageLayout().add(reportButton); - HorizontalLayout filtersLayout = new HorizontalLayout(equipoComboBox, semanaComboBox); + final HorizontalLayout filtersLayout = new HorizontalLayout(equipoComboBox, semanaComboBox); getCurrentPageLayout().add(filtersLayout); getCurrentPageLayout().add(headerLayout); @@ -98,9 +98,8 @@ public class ReporteView extends BaseView { 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), + final LocalDate startOfYear = LocalDate.of(year, 1, 5); // Suponemos que la semana comienza el 5 de enero. + final List weeks = startOfYear.datesUntil(LocalDate.of(year + 1, 1, 1), java.time.Period.ofWeeks(1)) .map(date -> { int weekNumber = date.get(WeekFields.of(DayOfWeek.MONDAY, 1) @@ -117,30 +116,30 @@ public class ReporteView extends BaseView { }) .collect(Collectors.toList()); - semanaComboBox.setItems(semanas); + semanaComboBox.setItems(weeks); semanaComboBox.setPlaceholder("Seleccione una semana"); } private void generateHoursWorkedReport() { - Team selectedEquipo = equipoComboBox.getValue(); - String selectedWeek = semanaComboBox.getValue(); - if (selectedEquipo == null || selectedWeek == null) { + final Team selectedTeam = equipoComboBox.getValue(); + final String selectedWeek = semanaComboBox.getValue(); + + if (selectedTeam == null || selectedWeek == null) { Notification.show("Por favor, selecciona un equipo y una semana para generar el reporte.", 3000, Notification.Position.MIDDLE); return; } - int weekNumber = Integer.parseInt(selectedWeek.split(" ")[1].replace(":", "")); - LocalDate selectedDate = LocalDate.now().with(WeekFields.of(DayOfWeek.FRIDAY, 1) + final int weekNumber = Integer.parseInt(selectedWeek.split(" ")[1].replace(":", "")); + final LocalDate selectedDate = LocalDate.now().with(WeekFields.of(DayOfWeek.FRIDAY, 1) .weekOfWeekBasedYear(), weekNumber); - updateHeaderLayout(selectedEquipo, selectedDate); + updateHeaderLayout(selectedTeam, selectedDate); - List hoursWorkedList = hoursWorkedService.findAll().stream() - .filter(hw -> hw.getEmployee().getTeam().getId().equals(selectedEquipo + final List hoursWorkedList = hoursWorkedService.findAll().stream() + .filter(hw -> hw.getEmployee().getTeam().getId().equals(selectedTeam .getId()) && hw.getWeekNumber() == weekNumber) - .collect(Collectors.toList()); + .toList(); - System.out.println(hoursWorkedList); if (hoursWorkedList.isEmpty()) { Notification.show("No hay horas trabajadas disponibles para generar el reporte.", @@ -155,8 +154,8 @@ public class ReporteView extends BaseView { 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("Horas Trabajadas", hoursWorked.getHours()); + map.put("Horas Pendientes", 40 - hoursWorked.getHours()); map.put("Observaciones", ""); return map; }) diff --git a/src/main/java/com/primefactorsolutions/views/TimesheetView.java b/src/main/java/com/primefactorsolutions/views/TimesheetView.java deleted file mode 100644 index 9a8b351..0000000 --- a/src/main/java/com/primefactorsolutions/views/TimesheetView.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.primefactorsolutions.views; - -import com.vaadin.flow.component.html.Main; -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.context.annotation.Scope; - -@SpringComponent -@PermitAll -@Scope("prototype") -@PageTitle("Timesheet") -@Route(value = "/timesheets/me", layout = MainLayout.class) -public class TimesheetView extends Main { -} - diff --git a/src/main/java/com/primefactorsolutions/views/util/AuthUtils.java b/src/main/java/com/primefactorsolutions/views/util/AuthUtils.java new file mode 100644 index 0000000..aee50f3 --- /dev/null +++ b/src/main/java/com/primefactorsolutions/views/util/AuthUtils.java @@ -0,0 +1,16 @@ +package com.primefactorsolutions.views.util; + +import com.vaadin.flow.spring.security.AuthenticationContext; +import lombok.experimental.UtilityClass; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +@UtilityClass +public class AuthUtils { + public static boolean isAdmin(final AuthenticationContext authenticationContext) { + return authenticationContext.getAuthenticatedUser(UserDetails.class).map(u -> + u.getAuthorities().stream() + .map(GrantedAuthority::getAuthority) + .anyMatch("ROLE_ADMIN"::equals)).orElse(false); + } +} diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 4969115..600d7ac 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -47,7 +47,8 @@ INSERT INTO vacation (id, version, category, expiration, type) VALUES ('490e5fbe INSERT INTO vacation (id, version, category, expiration, type) VALUES ('c23e4567-e89b-12d3-a456-4266141740ff', 1, 'VACACION_GESTION_ANTERIOR', 360, 'OTHER'); -insert into employee (id, version, username, first_name, last_name, status, team_id, gender, birthday, date_of_entry,lead_manager) values ('5c6f11fe-c341-4be7-a9a6-bba0081ad7c6', 1, 'bob', 'Bob', 'Test', 'ACTIVE','b0e8f394-78c1-4d8a-9c57-dc6e8b36a5fa', 'MALE', '2024-02-20', '2013-10-22',1);insert into employee (id, version, username, first_name, last_name, status, team_id, gender, date_of_entry) values ('cba3efb7-32bc-44be-9fdc-fc5e4f211254', 1, 'ben', 'Ben', 'Test', 'ACTIVE', '6d63bc15-3f8b-46f7-9cf1-7e9b0b9a2b28', 'MALE', '2016-10-23'); +insert into employee (id, version, username, first_name, last_name, status, team_id, gender, birthday, date_of_entry, lead_manager, role) values ('5c6f11fe-c341-4be7-a9a6-bba0081ad7c6', 1, 'bob', 'Bob', 'Test', 'ACTIVE','b0e8f394-78c1-4d8a-9c57-dc6e8b36a5fa', 'MALE', '2024-02-20', '2013-10-22', 'ben', 'ADMIN'); +insert into employee (id, version, username, first_name, last_name, status, team_id, gender, date_of_entry, role) values ('cba3efb7-32bc-44be-9fdc-fc5e4f211254', 1, 'ben', 'Ben', 'Test', 'ACTIVE', '6d63bc15-3f8b-46f7-9cf1-7e9b0b9a2b28', 'MALE', '2016-10-23', 'USER'); insert into employee (id, version, username, first_name, last_name, status, team_id, gender, date_of_entry) values ('e99b7af5-7d3a-4c0f-b8bc-e8d0388d8fc4', 1, 'jperez', 'Juan', 'Perez Condori', 'INACTIVE', 'c3a8a7b1-f2d9-48c0-86ea-f215c2e6b3a3', 'MALE', '2022-10-22'); insert into employee (id, version, username, first_name, last_name, status, team_id, gender, date_of_entry) values ('f6ab3c6d-7078-45f6-9b22-4e37637bfec6', 1, 'agarcia', 'Ana', 'Garcia Rojas', 'ACTIVE', '8f6b61e7-efb2-4de7-b8ed-7438c9d8babe', 'FEMALE', '2024-10-24'); insert into employee (id, version, username, first_name, last_name, status, team_id, gender) values ('2e2293b1-3f9a-4f3d-abc8-32639b0a5e15', 1, 'clopez', 'Carlos', 'Lopez Mendoza', 'INACTIVE', 'b0e8f394-78c1-4d8a-9c57-dc6e8b36a5fa', 'MALE'); @@ -90,4 +91,5 @@ values ('12ec8b74-983d-4a17-b67e-134f45ae904c', 1, '5c1a7b82-832d-4f24-8377-54b7 insert into time_off_request (id, version, employee_id, category, state, available_days, expiration, start_date, end_date, days_to_be_take, days_balance) values ('89bc4b2a-943f-487c-a9f3-bacf78145e67', 1, 'cba3efb7-32bc-44be-9fdc-fc5e4f211254', 'LUNES_CARNAVAL', 'APROBADO', 1, '2024-02-12', '2024-02-12', '2024-02-12', 1, 0); -insert into hours_worked (id, version, actividad, date, horaspendientes, hours, total_hours,week_number,employee_id,team_id) values ('389389ce-7b2e-4f39-aa06-2a251a2b35ea ',0,'meet','2024-11-27',0,4,0,48,'5c6f11fe-c341-4be7-a9a6-bba0081ad7c6','b0e8f394-78c1-4d8a-9c57-dc6e8b36a5fa'); \ No newline at end of file +insert into hours_worked (id, version, task, activity, date, hours, employee_id, team_id) +values ('389389ce-7b2e-4f39-aa06-2a251a2b35ea', 0, 'coding', 'meet', '2024-11-27', 4, '5c6f11fe-c341-4be7-a9a6-bba0081ad7c6', 'b0e8f394-78c1-4d8a-9c57-dc6e8b36a5fa'); \ No newline at end of file diff --git a/src/main/resources/test-server.ldif b/src/main/resources/test-server.ldif index 7b2afdb..3fa23c0 100644 --- a/src/main/resources/test-server.ldif +++ b/src/main/resources/test-server.ldif @@ -22,7 +22,7 @@ objectclass: inetOrgPerson cn: Ben User sn: BenUser uid: ben -userPassword: $2a$10$c6bSeWPhg06xB1lvmaWNNe4NROmZiSpYhlocU/98HNr2MhIOiSt36 +userPassword: benspassword dn: uid=bob,ou=users,dc=primefactorsolutions,dc=com objectclass: top