renamed timesheet entries
All checks were successful
Builder / Build-Project (push) Successful in 2m58s

This commit is contained in:
alex 2024-12-29 10:15:56 -05:00
parent cc805a49c4
commit 48cbea25c3
16 changed files with 163 additions and 223 deletions

Binary file not shown.

View File

@ -1,42 +0,0 @@
package com.primefactorsolutions.model;
import jakarta.persistence.*;
import lombok.*;
import java.time.LocalDate;
import java.time.temporal.IsoFields;
import java.util.List;
@Data
@Entity
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class HoursWorked extends BaseEntity {
private String task;
private String activity;
private LocalDate date;
private double hours;
@ManyToOne
@JoinColumn(name = "employee_id")
private Employee employee;
@ManyToOne
@JoinColumn(name = "team_id")
private Team team;
public static double calculateTotalHours(final List<HoursWorked> activities) {
return activities.stream()
.mapToDouble(activity -> activity.hours)
.sum();
}
public static double calculatePendingHours(final List<HoursWorked> activities) {
double totalHoursWorked = calculateTotalHours(activities);
return Math.max(0, 40 - totalHoursWorked);
}
public int getWeekNumber() {
return date.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR);
}
}

View File

@ -1,21 +0,0 @@
package com.primefactorsolutions.model;
import io.hypersistence.utils.hibernate.type.json.JsonType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.Type;
import java.util.List;
@Entity
@Data
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class Timesheet extends BaseEntity {
@Type(JsonType.class)
@Column(columnDefinition = "json")
private List<TimesheetEntry> entries;
}

View File

@ -1,13 +1,30 @@
package com.primefactorsolutions.model; package com.primefactorsolutions.model;
import lombok.AllArgsConstructor; import jakarta.persistence.*;
import lombok.Data; import lombok.*;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
import java.time.temporal.IsoFields;
@Data @Data
@Entity
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
public class TimesheetEntry { @EqualsAndHashCode(callSuper = true)
private TaskType taskType; public class TimesheetEntry extends BaseEntity {
private int hours;
private String task;
private String details;
private LocalDate date;
private double hours;
@ManyToOne
@JoinColumn(name = "employee_id")
private Employee employee;
@ManyToOne
@JoinColumn(name = "team_id")
private Team team;
public int getWeekNumber() {
return date.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR);
}
} }

View File

@ -1,12 +1,12 @@
package com.primefactorsolutions.repositories; package com.primefactorsolutions.repositories;
import com.primefactorsolutions.model.HoursWorked; import com.primefactorsolutions.model.TimesheetEntry;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
public interface HoursWorkedRepository extends JpaRepository<HoursWorked, UUID> { public interface HoursWorkedRepository extends JpaRepository<TimesheetEntry, UUID> {
List<HoursWorked> findByEmployeeIdAndDateBetween(UUID employeeId, LocalDate from, LocalDate to); List<TimesheetEntry> findByEmployeeIdAndDateBetween(UUID employeeId, LocalDate from, LocalDate to);
} }

View File

@ -1,6 +1,6 @@
package com.primefactorsolutions.service; package com.primefactorsolutions.service;
import com.primefactorsolutions.model.HoursWorked; import com.primefactorsolutions.model.TimesheetEntry;
import com.primefactorsolutions.repositories.HoursWorkedRepository; import com.primefactorsolutions.repositories.HoursWorkedRepository;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -11,28 +11,28 @@ import java.time.temporal.WeekFields;
import java.util.*; import java.util.*;
@Service @Service
public class HoursWorkedService { public class TimesheetService {
private final HoursWorkedRepository hoursWorkedRepository; private final HoursWorkedRepository hoursWorkedRepository;
@Autowired @Autowired
public HoursWorkedService(final HoursWorkedRepository hoursWorkedRepository) { public TimesheetService(final HoursWorkedRepository hoursWorkedRepository) {
this.hoursWorkedRepository = hoursWorkedRepository; this.hoursWorkedRepository = hoursWorkedRepository;
} }
public List<HoursWorked> findAll() { public List<TimesheetEntry> findAll() {
return hoursWorkedRepository.findAll(); return hoursWorkedRepository.findAll();
} }
public HoursWorked save(final HoursWorked hoursWorked) { public TimesheetEntry save(final TimesheetEntry timesheetEntry) {
return hoursWorkedRepository.save(hoursWorked); return hoursWorkedRepository.save(timesheetEntry);
} }
public HoursWorked getHoursWorked(final UUID id) { public TimesheetEntry getHoursWorked(final UUID id) {
final Optional<HoursWorked> hoursWorked = hoursWorkedRepository.findById(id); final Optional<TimesheetEntry> hoursWorked = hoursWorkedRepository.findById(id);
return hoursWorked.orElse(null); return hoursWorked.orElse(null);
} }
public List<HoursWorked> findListHoursWorkedEmployee(final UUID employeeId, final int weekNumber) { public List<TimesheetEntry> findListHoursWorkedEmployee(final UUID employeeId, final int weekNumber) {
final LocalDate from = getFirstDayOfWeek(weekNumber); final LocalDate from = getFirstDayOfWeek(weekNumber);
final LocalDate to = from.plusDays(7); final LocalDate to = from.plusDays(7);

View File

@ -1,6 +1,11 @@
package com.primefactorsolutions.views; package com.primefactorsolutions.views;
import com.primefactorsolutions.model.Employee; import com.primefactorsolutions.model.Employee;
import com.primefactorsolutions.views.timeoff.TimeOffNewRequestView;
import com.primefactorsolutions.views.timeoff.TimeOffPendingRequestsListView;
import com.primefactorsolutions.views.timeoff.TimeOffRequestListView;
import com.primefactorsolutions.views.timesheet.TimesheetListView;
import com.primefactorsolutions.views.timesheet.TimesheetReportView;
import com.vaadin.flow.component.Component; import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.Text; import com.vaadin.flow.component.Text;
import com.vaadin.flow.component.applayout.AppLayout; import com.vaadin.flow.component.applayout.AppLayout;

View File

@ -1,9 +1,10 @@
package com.primefactorsolutions.views; package com.primefactorsolutions.views.timeoff;
import com.primefactorsolutions.model.*; import com.primefactorsolutions.model.*;
import com.primefactorsolutions.service.EmployeeService; import com.primefactorsolutions.service.EmployeeService;
import com.primefactorsolutions.service.TimeOffRequestService; import com.primefactorsolutions.service.TimeOffRequestService;
import com.primefactorsolutions.service.VacationService; import com.primefactorsolutions.service.VacationService;
import com.primefactorsolutions.views.MainLayout;
import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.combobox.ComboBox; import com.vaadin.flow.component.combobox.ComboBox;
import com.vaadin.flow.component.datepicker.DatePicker; import com.vaadin.flow.component.datepicker.DatePicker;

View File

@ -1,9 +1,11 @@
package com.primefactorsolutions.views; package com.primefactorsolutions.views.timeoff;
import com.primefactorsolutions.model.*; import com.primefactorsolutions.model.*;
import com.primefactorsolutions.service.EmployeeService; import com.primefactorsolutions.service.EmployeeService;
import com.primefactorsolutions.service.TeamService; import com.primefactorsolutions.service.TeamService;
import com.primefactorsolutions.service.TimeOffRequestService; import com.primefactorsolutions.service.TimeOffRequestService;
import com.primefactorsolutions.views.BaseView;
import com.primefactorsolutions.views.MainLayout;
import com.primefactorsolutions.views.util.MenuBarUtils; import com.primefactorsolutions.views.util.MenuBarUtils;
import com.vaadin.flow.component.ClickEvent; import com.vaadin.flow.component.ClickEvent;
import com.vaadin.flow.component.Component; import com.vaadin.flow.component.Component;

View File

@ -1,10 +1,12 @@
package com.primefactorsolutions.views; package com.primefactorsolutions.views.timeoff;
import com.primefactorsolutions.model.*; import com.primefactorsolutions.model.*;
import com.primefactorsolutions.service.EmployeeService; import com.primefactorsolutions.service.EmployeeService;
import com.primefactorsolutions.service.TeamService; import com.primefactorsolutions.service.TeamService;
import com.primefactorsolutions.service.TimeOffRequestService; import com.primefactorsolutions.service.TimeOffRequestService;
import com.primefactorsolutions.service.VacationService; import com.primefactorsolutions.service.VacationService;
import com.primefactorsolutions.views.BaseView;
import com.primefactorsolutions.views.MainLayout;
import com.vaadin.flow.component.ClickEvent; import com.vaadin.flow.component.ClickEvent;
import com.vaadin.flow.component.Component; import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.ComponentEventListener; import com.vaadin.flow.component.ComponentEventListener;

View File

@ -1,9 +1,10 @@
package com.primefactorsolutions.views; package com.primefactorsolutions.views.timeoff;
import com.primefactorsolutions.model.*; import com.primefactorsolutions.model.*;
import com.primefactorsolutions.service.EmployeeService; import com.primefactorsolutions.service.EmployeeService;
import com.primefactorsolutions.service.TeamService; import com.primefactorsolutions.service.TeamService;
import com.primefactorsolutions.service.TimeOffRequestService; import com.primefactorsolutions.service.TimeOffRequestService;
import com.primefactorsolutions.views.MainLayout;
import com.vaadin.flow.component.Component; import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.combobox.ComboBox; import com.vaadin.flow.component.combobox.ComboBox;

View File

@ -1,9 +1,11 @@
package com.primefactorsolutions.views; package com.primefactorsolutions.views.timeoff;
import com.primefactorsolutions.model.*; import com.primefactorsolutions.model.*;
import com.primefactorsolutions.service.EmployeeService; import com.primefactorsolutions.service.EmployeeService;
import com.primefactorsolutions.service.TimeOffRequestService; import com.primefactorsolutions.service.TimeOffRequestService;
import com.primefactorsolutions.service.VacationService; import com.primefactorsolutions.service.VacationService;
import com.primefactorsolutions.views.BaseView;
import com.primefactorsolutions.views.MainLayout;
import com.vaadin.flow.component.ClickEvent; import com.vaadin.flow.component.ClickEvent;
import com.vaadin.flow.component.Component; import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.ComponentEventListener; import com.vaadin.flow.component.ComponentEventListener;
@ -651,10 +653,11 @@ public class TimeOffRequestsByEmployeeView extends BaseView implements HasUrlPar
} }
private void setViewTitle(final String employeeName, final String employeeTeam, final LocalDate dateOfExit) { private void setViewTitle(final String employeeName, final String employeeTeam, final LocalDate dateOfExit) {
addComponentAsFirst(new H3("Nombre del empleado: " + employeeName)); getCurrentPageLayout().addComponentAsFirst(new H3("Nombre del empleado: " + employeeName));
addComponentAtIndex(1, new H3("Equipo: " + employeeTeam)); getCurrentPageLayout().addComponentAtIndex(1, new H3("Equipo: " + employeeTeam));
if (dateOfExit != null) { if (dateOfExit != null) {
addComponentAtIndex( getCurrentPageLayout().addComponentAtIndex(
2, new H3("Descontado a cero en fecha " 2, new H3("Descontado a cero en fecha "
+ dateOfExit + dateOfExit
+ " por pago de finiquito incluidas duodecima.")); + " por pago de finiquito incluidas duodecima."));

View File

@ -1,13 +1,13 @@
package com.primefactorsolutions.views; package com.primefactorsolutions.views.timesheet;
import com.primefactorsolutions.model.Employee; import com.primefactorsolutions.model.Employee;
import com.primefactorsolutions.model.HoursWorked; import com.primefactorsolutions.model.TimesheetEntry;
import com.primefactorsolutions.model.Team; import com.primefactorsolutions.model.Team;
import com.primefactorsolutions.service.EmployeeService; import com.primefactorsolutions.service.EmployeeService;
import com.primefactorsolutions.service.HoursWorkedService; import com.primefactorsolutions.service.TimesheetService;
import com.primefactorsolutions.service.TeamService; import com.primefactorsolutions.service.TeamService;
import com.primefactorsolutions.views.MainLayout;
import com.vaadin.flow.component.Component; 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.NumberField;
import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.button.Button;
@ -32,30 +32,32 @@ import java.util.stream.Collectors;
@Scope("prototype") @Scope("prototype")
@PageTitle("Horas Trabajadas") @PageTitle("Horas Trabajadas")
@Route(value = "/timesheet/:hours-workedId?/:action?", layout = MainLayout.class) @Route(value = "/timesheet/:hours-workedId?/:action?", layout = MainLayout.class)
public class TimesheetRecordView extends BeanValidationForm<HoursWorked> implements HasUrlParameter<String> { public class TimesheetEntryView extends BeanValidationForm<TimesheetEntry> implements HasUrlParameter<String> {
private final ComboBox<Team> team = new ComboBox<>("Equipo"); private final ComboBox<Team> team = new ComboBox<>("Equipo");
private ComboBox<Employee> employee; private ComboBox<Employee> employee;
private final ComboBox<String> task = new ComboBox<>("Tarea Específica"); private final ComboBox<String> task = new ComboBox<>("Tarea");
private final TextField activity = new TextField("Actividad"); private final TextField details = new TextField("Detalle");
private final VDatePicker date = new VDatePicker("Fecha"); private final VDatePicker date = new VDatePicker("Fecha");
private final NumberField hours = new NumberField("Horas Tarea Específica"); private final NumberField hours = new NumberField("Horas");
private Button saveButton; private Button saveButton;
private final HoursWorkedService hoursWorkedService; private final TimesheetService timesheetService;
private final EmployeeService employeeService; private final EmployeeService employeeService;
private final TeamService teamService; private final TeamService teamService;
private HoursWorked hoursWorked; private TimesheetEntry timesheetEntry;
public TimesheetRecordView(final HoursWorkedService hoursWorkedService, public TimesheetEntryView(final TimesheetService timesheetService,
final EmployeeService employeeService, final EmployeeService employeeService,
final TeamService teamService) { final TeamService teamService) {
super(HoursWorked.class); super(TimesheetEntry.class);
this.hoursWorkedService = hoursWorkedService; this.timesheetService = timesheetService;
this.employeeService = employeeService; this.employeeService = employeeService;
this.teamService = teamService; this.teamService = teamService;
task.setRequired(true);
initializeDateField(); initializeDateField();
initializeTeamField(); initializeTeamField();
initializeEmployeeField(); initializeEmployeeField();
@ -68,11 +70,11 @@ public class TimesheetRecordView extends BeanValidationForm<HoursWorked> impleme
final String s = params.get("hours-workedId").orElse(null); final String s = params.get("hours-workedId").orElse(null);
if ("new".equals(action) || s == null) { if ("new".equals(action) || s == null) {
setEntityWithEnabledSave(new HoursWorked()); setEntityWithEnabledSave(new TimesheetEntry());
} else { } else {
final UUID hoursWorkedId = UUID.fromString(s); final UUID hoursWorkedId = UUID.fromString(s);
hoursWorked = hoursWorkedService.getHoursWorked(hoursWorkedId); timesheetEntry = timesheetService.getHoursWorked(hoursWorkedId);
setEntityWithEnabledSave(hoursWorked); setEntityWithEnabledSave(timesheetEntry);
if ("edit".equals(action) && !s.isEmpty()) { if ("edit".equals(action) && !s.isEmpty()) {
saveButton.setVisible(true); saveButton.setVisible(true);
@ -88,8 +90,8 @@ public class TimesheetRecordView extends BeanValidationForm<HoursWorked> impleme
date, date,
team, team,
employee, employee,
activity,
task, task,
details,
hours, hours,
createCloseButton() createCloseButton()
); );
@ -154,8 +156,7 @@ public class TimesheetRecordView extends BeanValidationForm<HoursWorked> impleme
} }
private String getEmployeeFullName(final Employee employee) { private String getEmployeeFullName(final Employee employee) {
return "TODOS".equals(employee.getFirstName()) return employee.getFirstName() + " " + employee.getLastName();
? "TODOS" : employee.getFirstName() + " " + employee.getLastName();
} }
private void initializeDateField() { private void initializeDateField() {
@ -170,47 +171,29 @@ public class TimesheetRecordView extends BeanValidationForm<HoursWorked> impleme
private void saveHoursWorked() { private void saveHoursWorked() {
if (isFormValid()) { if (isFormValid()) {
HoursWorked hoursWorked = getEntity(); final TimesheetEntry timesheetEntry = getEntity();
String actividad = this.activity.getValue(); final String details = this.details.getValue();
String tareaEspecifica = task.getValue(); final String task = this.task.getValue();
if (actividad != null && !actividad.isEmpty() && tareaEspecifica != null) { timesheetEntry.setDetails(details);
Notification.show("Solo puedes elegir una: actividad del proyecto o tarea de la empresa.", timesheetEntry.setTask(task);
3000, Notification.Position.BOTTOM_CENTER);
return;
}
if (actividad != null && !actividad.isEmpty()) { setFieldValues(timesheetEntry);
hoursWorked.setActivity(actividad); timesheetService.save(timesheetEntry);
} 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(); closeForm();
} }
} }
private void setFieldValues(final HoursWorked hoursWorked) { private void setFieldValues(final TimesheetEntry timesheetEntry) {
hoursWorked.setDate(date.getValue()); timesheetEntry.setDate(date.getValue());
hoursWorked.setTeam(team.getValue()); timesheetEntry.setTeam(team.getValue());
hoursWorked.setEmployee(employee.getValue()); timesheetEntry.setEmployee(employee.getValue());
hoursWorked.setActivity(activity.getValue()); timesheetEntry.setDetails(details.getValue());
hoursWorked.setHours(hours.getValue()); timesheetEntry.setHours(hours.getValue());
} }
private void closeForm() { private void closeForm() {
if (hoursWorked != null) { getUI().ifPresent(ui -> ui.navigate(TimesheetListView.class));
getUI().ifPresent(ui -> ui.navigate(TimesheetRecordView.class,
hoursWorked.getEmployee().getId().toString() + "/view"));
} else {
getUI().ifPresent(ui -> ui.navigate(TimesheetListView.class));
}
} }
private boolean isFormValid() { private boolean isFormValid() {

View File

@ -1,11 +1,13 @@
package com.primefactorsolutions.views; package com.primefactorsolutions.views.timesheet;
import com.primefactorsolutions.model.Employee; import com.primefactorsolutions.model.Employee;
import com.primefactorsolutions.model.HoursWorked; import com.primefactorsolutions.model.TimesheetEntry;
import com.primefactorsolutions.model.Team; import com.primefactorsolutions.model.Team;
import com.primefactorsolutions.service.EmployeeService; import com.primefactorsolutions.service.EmployeeService;
import com.primefactorsolutions.service.HoursWorkedService; import com.primefactorsolutions.service.TimesheetService;
import com.primefactorsolutions.service.TeamService; import com.primefactorsolutions.service.TeamService;
import com.primefactorsolutions.views.BaseView;
import com.primefactorsolutions.views.MainLayout;
import com.primefactorsolutions.views.util.MenuBarUtils; import com.primefactorsolutions.views.util.MenuBarUtils;
import com.vaadin.flow.component.ClickEvent; import com.vaadin.flow.component.ClickEvent;
import com.vaadin.flow.component.Component; import com.vaadin.flow.component.Component;
@ -16,7 +18,6 @@ import com.vaadin.flow.component.contextmenu.MenuItem;
import com.vaadin.flow.component.icon.VaadinIcon; import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.menubar.MenuBar; import com.vaadin.flow.component.menubar.MenuBar;
import com.vaadin.flow.component.menubar.MenuBarVariant; import com.vaadin.flow.component.menubar.MenuBarVariant;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout; import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.function.ValueProvider; import com.vaadin.flow.function.ValueProvider;
import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.PageTitle;
@ -39,19 +40,19 @@ import static com.primefactorsolutions.views.Constants.PAGE_SIZE;
@Route(value = "/timesheet/records", layout = MainLayout.class) @Route(value = "/timesheet/records", layout = MainLayout.class)
public class TimesheetListView extends BaseView { public class TimesheetListView extends BaseView {
private final HoursWorkedService hoursWorkedService; private final TimesheetService timesheetService;
private final EmployeeService employeeService; private final EmployeeService employeeService;
private final TeamService teamService; private final TeamService teamService;
private final PagingGrid<HoursWorked> hoursWorkedGrid = new PagingGrid<>(); private final PagingGrid<TimesheetEntry> timesheetPagingGrid = new PagingGrid<>();
private ComboBox<Employee> employeeFilter; private ComboBox<Employee> employeeFilter;
private ComboBox<Team> teamFilter; private ComboBox<Team> teamFilter;
public TimesheetListView(final AuthenticationContext authenticationContext, public TimesheetListView(final AuthenticationContext authenticationContext,
final HoursWorkedService hoursWorkedService, final TimesheetService timesheetService,
final EmployeeService employeeService, final EmployeeService employeeService,
final TeamService teamService) { final TeamService teamService) {
super(authenticationContext); super(authenticationContext);
this.hoursWorkedService = hoursWorkedService; this.timesheetService = timesheetService;
this.employeeService = employeeService; this.employeeService = employeeService;
this.teamService = teamService; this.teamService = teamService;
@ -61,51 +62,42 @@ public class TimesheetListView extends BaseView {
private void refreshGridListHoursWorked(final Employee employee, private void refreshGridListHoursWorked(final Employee employee,
final Team team) { final Team team) {
hoursWorkedGrid.setPagingDataProvider((page, pageSize) -> { timesheetPagingGrid.setPagingDataProvider((page, pageSize) -> {
int start = (int) (page * hoursWorkedGrid.getPageSize()); final int start = (int) (page * timesheetPagingGrid.getPageSize());
List<HoursWorked> hoursWorkedList = fetchFilteredHoursWorked(start, pageSize, employee, team); return fetchFilteredHoursWorked(start, pageSize, employee, team);
double totalHours = hoursWorkedList.stream()
.mapToDouble(HoursWorked::getHours)
.sum();
Notification.show("Total de horas trabajadas: " + totalHours,
3000, Notification.Position.BOTTOM_CENTER);
return hoursWorkedList;
}); });
hoursWorkedGrid.getDataProvider().refreshAll(); timesheetPagingGrid.getDataProvider().refreshAll();
} }
private List<HoursWorked> fetchFilteredHoursWorked(final int start, private List<TimesheetEntry> fetchFilteredHoursWorked(final int start,
final int pageSize, final int pageSize,
final Employee employee, final Employee employee,
final Team team) { final Team team) {
List<HoursWorked> filteredHoursWorked = hoursWorkedService.findAll(); List<TimesheetEntry> filteredTimesheetEntry = timesheetService.findAll();
if (employee != null) { if (employee != null) {
filteredHoursWorked = filteredHoursWorked.stream() filteredTimesheetEntry = filteredTimesheetEntry.stream()
.filter(hw -> hw.getEmployee().getId().equals(employee.getId())) .filter(hw -> hw.getEmployee().getId().equals(employee.getId()))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
if (team != null) { if (team != null) {
filteredHoursWorked = filteredHoursWorked.stream() filteredTimesheetEntry = filteredTimesheetEntry.stream()
.filter(hw -> hw.getEmployee().getTeam() != null .filter(hw -> hw.getEmployee().getTeam() != null
&& hw.getEmployee().getTeam().getId().equals(team.getId())) && hw.getEmployee().getTeam().getId().equals(team.getId()))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
int end = Math.min(start + pageSize, filteredHoursWorked.size()); int end = Math.min(start + pageSize, filteredTimesheetEntry.size());
return filteredHoursWorked.subList(start, end); return filteredTimesheetEntry.subList(start, end);
} }
private void initializeView() { private void initializeView() {
getCurrentPageLayout().add(createAddHoursWorked()); getCurrentPageLayout().add(createAddHoursWorked());
setupFilters(); setupFilters();
setupListHoursWorkedGrid(); setupListHoursWorkedGrid();
getCurrentPageLayout().add(hoursWorkedGrid); getCurrentPageLayout().add(timesheetPagingGrid);
} }
private void setupFilters() { private void setupFilters() {
@ -117,23 +109,23 @@ public class TimesheetListView extends BaseView {
} }
private void setupListHoursWorkedGrid() { private void setupListHoursWorkedGrid() {
hoursWorkedGrid.addColumn(hw -> hw.getDate() != null ? hw.getDate().toString() : "") timesheetPagingGrid.addColumn(hw -> hw.getDate() != null ? hw.getDate().toString() : "")
.setHeader("Fecha") .setHeader("Fecha")
.setSortable(true); .setSortable(true);
hoursWorkedGrid.addColumn(HoursWorked::getWeekNumber) timesheetPagingGrid.addColumn(TimesheetEntry::getWeekNumber)
.setHeader("Semana") .setHeader("Semana")
.setSortable(true); .setSortable(true);
hoursWorkedGrid.addColumn(hw -> hw.getEmployee().getFirstName() + " " + hw.getEmployee().getLastName()) timesheetPagingGrid.addColumn(hw -> hw.getEmployee().getFirstName() + " " + hw.getEmployee().getLastName())
.setHeader("Empleado"); .setHeader("Empleado");
hoursWorkedGrid.addColumn(hw -> hw.getEmployee().getTeam() != null ? hw.getEmployee().getTeam() timesheetPagingGrid.addColumn(hw -> hw.getEmployee().getTeam() != null ? hw.getEmployee().getTeam()
.getName() : "Sin asignar") .getName() : "Sin asignar")
.setHeader("Equipo"); .setHeader("Equipo");
hoursWorkedGrid.addColumn(hw -> { timesheetPagingGrid.addColumn(hw -> {
String actividad = hw.getActivity() != null ? hw.getActivity() : "Sin Actividad"; String details = hw.getDetails() != null ? hw.getDetails() : "Sin Detalle";
String tareaEspecifica = hw.getTask() != null ? hw.getTask() : ""; String task = hw.getTask() != null ? hw.getTask() : "";
return !tareaEspecifica.isEmpty() ? tareaEspecifica : actividad; return !task.isEmpty() ? task : details;
}).setHeader("Actividad"); }).setHeader("Details");
hoursWorkedGrid.addColumn(hw -> { timesheetPagingGrid.addColumn(hw -> {
if (hw.getTask() != null && !hw.getTask().isEmpty()) { if (hw.getTask() != null && !hw.getTask().isEmpty()) {
return calculateHoursPerTask(hw); return calculateHoursPerTask(hw);
} else { } else {
@ -141,9 +133,9 @@ public class TimesheetListView extends BaseView {
} }
}).setHeader("Total Horas").setSortable(true); }).setHeader("Total Horas").setSortable(true);
hoursWorkedGrid.addColumn(hw -> 40 - calculateTotal(hw)).setHeader("Horas Pendientes") timesheetPagingGrid.addColumn(hw -> 40 - calculateTotal(hw)).setHeader("Horas Pendientes")
.setSortable(true); .setSortable(true);
hoursWorkedGrid.addComponentColumn((ValueProvider<HoursWorked, Component>) hoursWorked -> { timesheetPagingGrid.addComponentColumn((ValueProvider<TimesheetEntry, Component>) hoursWorked -> {
final MenuBar menuBar = new MenuBar(); final MenuBar menuBar = new MenuBar();
menuBar.addThemeVariants(MenuBarVariant.LUMO_TERTIARY_INLINE); menuBar.addThemeVariants(MenuBarVariant.LUMO_TERTIARY_INLINE);
final MenuItem viewItem = MenuBarUtils.createIconItem(menuBar, VaadinIcon.EYE, "Ver"); final MenuItem viewItem = MenuBarUtils.createIconItem(menuBar, VaadinIcon.EYE, "Ver");
@ -153,33 +145,33 @@ public class TimesheetListView extends BaseView {
return menuBar; return menuBar;
}); });
hoursWorkedGrid.setPaginationBarMode(PagingGrid.PaginationBarMode.BOTTOM); timesheetPagingGrid.setPaginationBarMode(PagingGrid.PaginationBarMode.BOTTOM);
hoursWorkedGrid.setPageSize(PAGE_SIZE); timesheetPagingGrid.setPageSize(PAGE_SIZE);
} }
private double calculateHoursPerTask(final HoursWorked hoursWorked) { private double calculateHoursPerTask(final TimesheetEntry timesheetEntry) {
final List<HoursWorked> tasks = hoursWorkedService.findListHoursWorkedEmployee( final List<TimesheetEntry> tasks = timesheetService.findListHoursWorkedEmployee(
hoursWorked.getEmployee().getId(), hoursWorked.getWeekNumber()); timesheetEntry.getEmployee().getId(), timesheetEntry.getWeekNumber());
return tasks.stream() return tasks.stream()
.filter(hw -> Objects.equals(hw.getTask(), hoursWorked.getTask())) .filter(hw -> Objects.equals(hw.getTask(), timesheetEntry.getTask()))
.mapToDouble(HoursWorked::getHours) .mapToDouble(TimesheetEntry::getHours)
.sum(); .sum();
} }
private void navigateToHoursWorkedView(final UUID idRecord) { private void navigateToHoursWorkedView(final UUID idRecord) {
getUI().ifPresent(ui -> ui.navigate(TimesheetRecordView.class, idRecord.toString() + "/view")); getUI().ifPresent(ui -> ui.navigate(TimesheetEntryView.class, idRecord.toString() + "/view"));
} }
private double calculateTotal(final HoursWorked hoursWorked) { private double calculateTotal(final TimesheetEntry timesheetEntry) {
final List<HoursWorked> listHoursworkedEmployee = hoursWorkedService.findListHoursWorkedEmployee( final List<TimesheetEntry> listHoursworkedEmployee = timesheetService.findListHoursWorkedEmployee(
hoursWorked.getEmployee().getId(), hoursWorked.getWeekNumber()); timesheetEntry.getEmployee().getId(), timesheetEntry.getWeekNumber());
return calculateTotalUtilized(listHoursworkedEmployee); return calculateTotalUtilized(listHoursworkedEmployee);
} }
private double calculateTotalUtilized(final List<HoursWorked> employeeRequests) { private double calculateTotalUtilized(final List<TimesheetEntry> employeeRequests) {
return employeeRequests.stream() return employeeRequests.stream()
.filter(Objects::nonNull) .filter(Objects::nonNull)
.mapToDouble(HoursWorked::getHours) .mapToDouble(TimesheetEntry::getHours)
.sum(); .sum();
} }
@ -195,7 +187,7 @@ public class TimesheetListView extends BaseView {
} }
private void navigateToHours() { private void navigateToHours() {
getUI().ifPresent(ui -> ui.navigate(TimesheetRecordView.class, "new")); getUI().ifPresent(ui -> ui.navigate(TimesheetEntryView.class, "new"));
} }
private ComboBox<Employee> createEmployeeFilter() { private ComboBox<Employee> createEmployeeFilter() {
@ -216,8 +208,7 @@ public class TimesheetListView extends BaseView {
} }
private String getEmployeeFullName(final Employee employee) { private String getEmployeeFullName(final Employee employee) {
return "TODOS".equals(employee.getFirstName()) return employee.getFirstName() + " " + employee.getLastName();
? "TODOS" : employee.getFirstName() + " " + employee.getLastName();
} }
private ComboBox<Team> createTeamFilter() { private ComboBox<Team> createTeamFilter() {
@ -237,6 +228,6 @@ public class TimesheetListView extends BaseView {
} }
private String getTeamLabel(final Team team) { private String getTeamLabel(final Team team) {
return team != null && !"TODOS".equals(team.getName()) ? team.getName() : "TODOS"; return team.getName();
} }
} }

View File

@ -1,10 +1,12 @@
package com.primefactorsolutions.views; package com.primefactorsolutions.views.timesheet;
import com.primefactorsolutions.model.HoursWorked; import com.primefactorsolutions.model.TimesheetEntry;
import com.primefactorsolutions.model.Team; import com.primefactorsolutions.model.Team;
import com.primefactorsolutions.service.HoursWorkedService; import com.primefactorsolutions.service.TimesheetService;
import com.primefactorsolutions.service.ReportService; import com.primefactorsolutions.service.ReportService;
import com.primefactorsolutions.service.TeamService; import com.primefactorsolutions.service.TeamService;
import com.primefactorsolutions.views.BaseView;
import com.primefactorsolutions.views.MainLayout;
import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.combobox.ComboBox; import com.vaadin.flow.component.combobox.ComboBox;
import com.vaadin.flow.component.grid.Grid; import com.vaadin.flow.component.grid.Grid;
@ -39,7 +41,7 @@ import java.util.stream.Collectors;
public class TimesheetReportView extends BaseView { public class TimesheetReportView extends BaseView {
private final EmployeeService employeeService; private final EmployeeService employeeService;
private final HoursWorkedService hoursWorkedService; private final TimesheetService timesheetService;
private final ReportService reportService; private final ReportService reportService;
private final TeamService teamService; private final TeamService teamService;
private final ComboBox<Team> equipoComboBox = new ComboBox<>("Seleccionar Equipo"); private final ComboBox<Team> equipoComboBox = new ComboBox<>("Seleccionar Equipo");
@ -52,27 +54,24 @@ public class TimesheetReportView extends BaseView {
@Autowired @Autowired
public TimesheetReportView(final AuthenticationContext authenticationContext, public TimesheetReportView(final AuthenticationContext authenticationContext,
final HoursWorkedService hoursWorkedService, final TimesheetService timesheetService,
final ReportService reportService, final ReportService reportService,
final TeamService teamService, final TeamService teamService,
final EmployeeService employeeService) { final EmployeeService employeeService) {
super(authenticationContext); super(authenticationContext);
this.hoursWorkedService = hoursWorkedService; this.timesheetService = timesheetService;
this.reportService = reportService; this.reportService = reportService;
this.teamService = teamService; this.teamService = teamService;
this.employeeService = employeeService; this.employeeService = employeeService;
H2 title = new H2("Reporte de Horas Trabajadas"); final H2 title = new H2("Reporte de Horas Trabajadas");
getCurrentPageLayout().add(title); getCurrentPageLayout().add(title);
final List<Team> teams = teamService.findAllTeams(); final List<Team> teams = teamService.findAllTeams();
equipoComboBox.setItems(teams); equipoComboBox.setItems(teams);
equipoComboBox.setItemLabelGenerator(Team::getName); equipoComboBox.setItemLabelGenerator(Team::getName);
initializeWeekComboBox();
// Configurar el ComboBox de semanas
initializeSemanaComboBox();
// Listener para actualizar `semanaInfoSpan` con la selección del usuario en `semanaComboBox`
semanaComboBox.addValueChangeListener(event -> { semanaComboBox.addValueChangeListener(event -> {
String selectedWeek = event.getValue(); String selectedWeek = event.getValue();
semanaInfoSpan.setText(selectedWeek != null ? selectedWeek : "Selecciona una semana"); semanaInfoSpan.setText(selectedWeek != null ? selectedWeek : "Selecciona una semana");
@ -81,7 +80,6 @@ public class TimesheetReportView extends BaseView {
final Button reportButton = new Button("Generar Reporte de Horas Trabajadas", final Button reportButton = new Button("Generar Reporte de Horas Trabajadas",
event -> generateHoursWorkedReport()); event -> generateHoursWorkedReport());
getCurrentPageLayout().add(reportButton); getCurrentPageLayout().add(reportButton);
final HorizontalLayout filtersLayout = new HorizontalLayout(equipoComboBox, semanaComboBox); final HorizontalLayout filtersLayout = new HorizontalLayout(equipoComboBox, semanaComboBox);
getCurrentPageLayout().add(filtersLayout); getCurrentPageLayout().add(filtersLayout);
@ -96,15 +94,15 @@ public class TimesheetReportView extends BaseView {
getCurrentPageLayout().add(grid); getCurrentPageLayout().add(grid);
} }
private void initializeSemanaComboBox() { private void initializeWeekComboBox() {
int year = LocalDate.now().getYear(); int year = LocalDate.now().getYear();
final LocalDate startOfYear = LocalDate.of(year, 1, 5); // Suponemos que la semana comienza el 5 de enero. final LocalDate startOfYear = LocalDate.of(year, 1, 5);
final List<String> weeks = startOfYear.datesUntil(LocalDate.of(year + 1, 1, 1), final List<String> weeks = startOfYear.datesUntil(LocalDate.of(year + 1, 1, 1),
java.time.Period.ofWeeks(1)) java.time.Period.ofWeeks(1))
.map(date -> { .map(date -> {
int weekNumber = date.get(WeekFields.of(DayOfWeek.MONDAY, 1) final int weekNumber = date.get(
.weekOfWeekBasedYear()); WeekFields.of(DayOfWeek.MONDAY, 1).weekOfWeekBasedYear());
LocalDate endOfWeek = date.plusDays(6); final LocalDate endOfWeek = date.plusDays(6);
return String.format("Semana %d: %s - %s", return String.format("Semana %d: %s - %s",
weekNumber, weekNumber,
@ -135,19 +133,19 @@ public class TimesheetReportView extends BaseView {
.weekOfWeekBasedYear(), weekNumber); .weekOfWeekBasedYear(), weekNumber);
updateHeaderLayout(selectedTeam, selectedDate); updateHeaderLayout(selectedTeam, selectedDate);
final List<HoursWorked> hoursWorkedList = hoursWorkedService.findAll().stream() final List<TimesheetEntry> timesheetEntryList = timesheetService.findAll().stream()
.filter(hw -> hw.getEmployee().getTeam().getId().equals(selectedTeam .filter(hw -> hw.getEmployee().getTeam().getId().equals(selectedTeam
.getId()) && hw.getWeekNumber() == weekNumber) .getId()) && hw.getWeekNumber() == weekNumber)
.toList(); .toList();
if (hoursWorkedList.isEmpty()) { if (timesheetEntryList.isEmpty()) {
Notification.show("No hay horas trabajadas disponibles para generar el reporte.", Notification.show("No hay horas trabajadas disponibles para generar el reporte.",
3000, Notification.Position.MIDDLE); 3000, Notification.Position.MIDDLE);
return; return;
} }
List<Map<String, Object>> data = hoursWorkedList.stream() List<Map<String, Object>> data = timesheetEntryList.stream()
.map(hoursWorked -> { .map(hoursWorked -> {
Map<String, Object> map = new HashMap<>(); Map<String, Object> map = new HashMap<>();
map.put("ID", hoursWorked.getId().toString()); map.put("ID", hoursWorked.getId().toString());

View File

@ -91,5 +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) 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); 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, task, activity, date, hours, employee_id, team_id) insert into timesheet_entry (id, version, task, details, 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'); values ('389389ce-7b2e-4f39-aa06-2a251a2b35ea', 0, 'coding', 'meet', '2024-11-27', 4, '5c6f11fe-c341-4be7-a9a6-bba0081ad7c6', 'b0e8f394-78c1-4d8a-9c57-dc6e8b36a5fa');