Compare commits

..

No commits in common. "c67cdf868ea8478cf78a646f44c5c01059b0b6d6" and "3f17eb780bcb065ad58dbc235293a22fe2ec3260" have entirely different histories.

17 changed files with 704 additions and 466 deletions

View File

@ -0,0 +1,14 @@
name: PR Builder
run-name: ${{ gitea.actor }} building PR
on: [pull_request]
jobs:
Build-PR:
runs-on: ubuntu-22.04
steps:
- run: echo "The job was automatically triggered by a ${{ gitea.event_name }} event on branch ${{ gitea.head_ref }} and ref is ${{ gitea.ref }} and your repository is ${{ gitea.repository }}."
- name: Build PR
if: gitea.base_ref == 'main'
run: |
git clone --single-branch --branch "${{ gitea.head_ref }}" https://git.primefactorsolutions.com/PFS/pfs-intra.git && cd pfs-intra && ./mvnw clean package -Pproduction
- run: echo "This job's status is ${{ job.status }}."

View File

@ -0,0 +1,16 @@
name: Builder
run-name: ${{ gitea.actor }} building
on:
push:
branches:
- main
jobs:
Build-Project:
runs-on: ubuntu-22.04
steps:
- run: echo "The job was automatically triggered by a ${{ gitea.event_name }} event on branch is ${{ gitea.ref }} and your repository is ${{ gitea.repository }}."
- name: Build package
run: |
git clone --single-branch --branch main https://git.primefactorsolutions.com/PFS/pfs-intra.git && cd pfs-intra && ./mvnw clean package -Pproduction && unlink /home/ubuntu/pfs-intra/app.jar && cp target/*.jar /home/ubuntu/pfs-intra/app.jar && sudo systemctl restart pfs-intra
- run: echo "This job's status is ${{ job.status }}."

118
.mvn/wrapper/MavenWrapperDownloader.java vendored Normal file
View File

@ -0,0 +1,118 @@
/*
* Copyright 2007-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.*;
import java.net.*;
import java.nio.channels.*;
import java.util.Properties;
public class MavenWrapperDownloader {
private static final String WRAPPER_VERSION = "0.5.6";
/**
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is
* provided.
*/
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
/**
* Path to the maven-wrapper.properties file, which might contain a downloadUrl
* property to use instead of the default one.
*/
private static final String MAVEN_WRAPPER_PROPERTIES_PATH = ".mvn/wrapper/maven-wrapper.properties";
/**
* Path where the maven-wrapper.jar will be saved to.
*/
private static final String MAVEN_WRAPPER_JAR_PATH = ".mvn/wrapper/maven-wrapper.jar";
/**
* Name of the property which should be used to override the default download
* url for the wrapper.
*/
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
public static void main(String args[]) {
System.out.println("- Downloader started");
File baseDirectory = new File(args[0]);
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
// If the maven-wrapper.properties exists, read it and check if it contains a
// custom
// wrapperUrl parameter.
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
String url = DEFAULT_DOWNLOAD_URL;
if (mavenWrapperPropertyFile.exists()) {
FileInputStream mavenWrapperPropertyFileInputStream = null;
try {
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
Properties mavenWrapperProperties = new Properties();
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
} catch (IOException e) {
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
} finally {
try {
if (mavenWrapperPropertyFileInputStream != null) {
mavenWrapperPropertyFileInputStream.close();
}
} catch (IOException e) {
// Ignore ...
}
}
}
System.out.println("- Downloading from: " + url);
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
if (!outputFile.getParentFile().exists()) {
if (!outputFile.getParentFile().mkdirs()) {
System.out.println(
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
}
}
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
try {
downloadFileFromURL(url, outputFile);
System.out.println("Done");
System.exit(0);
} catch (Throwable e) {
System.out.println("- Error downloading");
e.printStackTrace();
System.exit(1);
}
}
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
String username = System.getenv("MVNW_USERNAME");
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
}
URL website = new URL(urlString);
ReadableByteChannel rbc;
rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream(destination);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
fos.close();
rbc.close();
}
}

BIN
.mvn/wrapper/maven-wrapper.jar vendored Normal file

Binary file not shown.

18
.mvn/wrapper/maven-wrapper.properties vendored Normal file
View File

@ -0,0 +1,18 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar

View File

@ -1,81 +0,0 @@
package com.primefactorsolutions.model;
import jakarta.persistence.*;
import java.time.LocalDate;
import java.util.UUID;
@Entity
@Table(name = "Actividades_hours")
public class ActividadesHours {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;
@ManyToOne
@JoinColumn(name = "employee_id", nullable = false)
private Employee employee;
@ManyToOne
@JoinColumn(name = "actividad_id", nullable = false)
private Actividad actividad;
@Column(nullable = false)
private double totalHours;
@Column(nullable = false)
private int weekNumber;
@Column(nullable = false)
private LocalDate fecha;
// Getters y Setters
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
public Actividad getActividad() {
return actividad;
}
public void setActividad(Actividad actividad) {
this.actividad = actividad;
}
public double getTotalHours() {
return totalHours;
}
public void setTotalHours(double totalHours) {
this.totalHours = totalHours;
}
public int getWeekNumber() {
return weekNumber;
}
public void setWeekNumber(int weekNumber) {
this.weekNumber = weekNumber;
}
public LocalDate getFecha() {
return fecha;
}
public void setFecha(LocalDate fecha) {
this.fecha = fecha;
}
}

View File

@ -28,40 +28,36 @@ public class Employee extends BaseEntity implements UserDetails {
@Pattern(regexp = "^[a-zA-Z ]+$", message = "El apellido solo debe contener letras") @Pattern(regexp = "^[a-zA-Z ]+$", message = "El apellido solo debe contener letras")
private String lastName; private String lastName;
private LocalDate birthday; private LocalDate birthday;
@Pattern(regexp = "^[a-zA-Z ,]+$", message = "La ciudad de nacimiento solo debe contener letras, espacios o comas") @Pattern(regexp = "^[a-zA-Z ]+$", message = "La ciudad de nacimiento solo debe contener letras")
private String birthCity; private String birthCity;
private String age; private String age;
@Size(max = 50, message = "La dirección de residencia no debe exceder 50 caracteres") @Size(max = 100, message = "La dirección de residencia no debe exceder 100 caracteres")
private String residenceAddress; private String residenceAddress;
@Size(max = 30, message = "La dirección local no debe exceder 100 caracteres") @Size(max = 100, message = "La dirección local no debe exceder 100 caracteres")
@Pattern(regexp = "^[a-zA-Z -]+$", message = "La dirección local solo debe contener letras y guion")
private String localAddress; private String localAddress;
@Pattern(regexp = "^[0-9]+$", message = "El número de teléfono debe contener solo números") @Pattern(regexp = "^[0-9]+$", message = "El número de teléfono debe contener solo números")
private String phoneNumber; private String phoneNumber;
@Email(message = "El correo personal no tiene un formato válido") @Email(message = "El correo personal no tiene un formato válido")
private String personalEmail; private String personalEmail;
@Pattern(regexp = "^[a-zA-Z ]+$", message = "El cargo solo debe contener letras") @Pattern(regexp = "^[a-zA-Z ]+$", message = "El cargo solo debe contener letras")
private String position; private String position;
@ManyToOne @ManyToOne
@JoinColumn(name = "team_id", nullable = false) @JoinColumn(name = "team_id", nullable = false)
private Team team; private Team team;
@Size(max = 100, message = "El nombre de contacto de emergencia no debe exceder 100 caracteres")
@Pattern(regexp = "^[a-zA-Z ]+$", message = "El nombre y apellido de contacto de emergencia solo debe contener letras")
private String emergencyCName; private String emergencyCName;
@Size(max = 100, message = "La dirección de contacto de emergencia no debe exceder 100 caracteres")
private String emergencyCAddress; private String emergencyCAddress;
@Pattern(regexp = "^[0-9]+$", message = "El teléfono de contacto de emergencia debe contener solo números") @Pattern(regexp = "^[0-9]+$", message = "El teléfono de contacto de emergencia debe contener solo números")
private String emergencyCPhone; private String emergencyCPhone;
@Email(message = "El correo de contacto de emergencia no tiene un formato válido") @Email(message = "El correo de contacto de emergencia no tiene un formato válido")
private String emergencyCEmail; private String emergencyCEmail;
@Max(value = 10, message = "El número de hijos no puede exceder a 10")
@Pattern(regexp = "^[0-9]+$", message = "La cantidad de hijos debe contener solo números") @Pattern(regexp = "^[0-9]+$", message = "La cantidad de hijos debe contener solo números")
private String numberOfChildren; private String numberOfChildren;
@Pattern(regexp = "^[0-9]+$", message = "El CI debe contener solo números") @Pattern(regexp = "^[0-9]+$", message = "El CI debe contener solo números")
private String ci; private String ci;
private String issuedIn; private String issuedIn;
@Size(max = 100, message = "El título no debe exceder 100 caracteres")
private String pTitle1; private String pTitle1;
private String pTitle2; private String pTitle2;
private String pTitle3; private String pTitle3;
@ -74,7 +70,9 @@ public class Employee extends BaseEntity implements UserDetails {
private String certification2; private String certification2;
private String certification3; private String certification3;
private String certification4; private String certification4;
@Size(max = 255, message = "El reconocimiento no debe exceder 255 caracteres")
private String recognition; private String recognition;
@Size(max = 500, message = "Los logros no deben exceder 500 caracteres")
private String achievements; private String achievements;
private String language; private String language;

View File

@ -1,43 +1,68 @@
package com.primefactorsolutions.model; package com.primefactorsolutions.model;
import jakarta.persistence.*; import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.CascadeType;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.temporal.WeekFields;
import java.util.Locale;
import java.util.UUID; import java.util.UUID;
@Data @Data
@Entity @Entity
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class HoursWorked extends BaseEntity { public class HoursWorked extends BaseEntity {
@Id @Id
@GeneratedValue(strategy = GenerationType.AUTO) @GeneratedValue(strategy = GenerationType.UUID)
private UUID id; private UUID id;
@ManyToOne @ManyToOne
@JoinColumn(name = "employee_id", nullable = false)
private Employee employee; private Employee employee;
@ManyToOne @ManyToOne(cascade = CascadeType.PERSIST) // Añadimos cascade para que persista la actividad automáticamente
@JoinColumn(name = "team_id", nullable = false) private Actividad actividad;
private Team team;
private int weekNumber; private int weekNumber;
private LocalDate date;
private String actividad;
private double hours;
private double totalHours; private double totalHours;
private LocalDate fecha;
public HoursWorked() {}
public HoursWorked(Employee employee) {
this.employee = employee;
this.weekNumber = 0;
this.totalHours = 0;
this.fecha = LocalDate.now();
}
public Actividad getActividad() {
return this.actividad;
}
public void setActividad(Actividad actividad){
this.actividad = actividad;
}
public UUID getId() {
return id;
}
public void setId(final UUID id) {
this.id = id;
}
public Employee getEmployee() { public Employee getEmployee() {
return employee; return employee;
} }
public void setEmployee(Employee employee) { public void setEmployee(final Employee employee) {
this.employee = employee; this.employee = employee;
} }
@ -45,48 +70,45 @@ public class HoursWorked extends BaseEntity {
return weekNumber; return weekNumber;
} }
public void setWeekNumber(int weekNumber) { public void setWeekNumber(final int weekNumber) {
this.weekNumber = weekNumber; this.weekNumber = weekNumber;
} }
public LocalDate getDate() {
return date;
}
public void setDate(LocalDate date) {
this.date = date;
}
public String getActividad() {
return actividad;
}
public void setActividad(String actividad) {
this.actividad = actividad;
}
public double getHours() {
return hours;
}
public void setHours(double hours) {
this.hours = hours;
}
public double getTotalHours() { public double getTotalHours() {
return totalHours; return totalHours;
} }
public void setTotalHours(double totalHours) { public void setTotalHours(final double totalHours) {
this.totalHours = totalHours; this.totalHours = totalHours;
} }
public Team getTeam() { public LocalDate getFecha() {
return team; return fecha;
} }
public void setTeam(Team team) { public void setFecha(final LocalDate fecha) {
this.team = team; this.fecha = fecha;
// Actualiza el número de semana automáticamente al establecer la fecha
if (fecha != null) {
this.weekNumber = calculateWeekNumber(fecha);
}
}
// Método adicional para calcular el número de semana basado en la fecha
private int calculateWeekNumber(LocalDate date) {
WeekFields weekFields = WeekFields.of(Locale.getDefault());
return date.get(weekFields.weekOfWeekBasedYear());
}
@Override
public String toString() {
return "HoursWorked{" +
"id=" + id +
", employee=" + (employee != null ? employee.getFirstName() : "N/A") +
", actividad=" + (actividad != null ? actividad.getNombre() : "N/A") +
", weekNumber=" + weekNumber +
", totalHours=" + totalHours +
", fecha=" + fecha +
'}';
} }
} }

View File

@ -1,7 +0,0 @@
package com.primefactorsolutions.repositories;
import com.primefactorsolutions.model.ActividadesHours;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.UUID;
public interface ActividadesHoursRepository extends JpaRepository<ActividadesHours,UUID> {
}

View File

@ -2,13 +2,11 @@ package com.primefactorsolutions.repositories;
import com.primefactorsolutions.model.HoursWorked; import com.primefactorsolutions.model.HoursWorked;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.time.LocalDate;
import java.util.List; import java.util.List;
import java.util.UUID;
@Repository
public interface HoursWorkedRepository extends JpaRepository<HoursWorked, UUID> { public interface HoursWorkedRepository extends JpaRepository<HoursWorked, Long> {
List<HoursWorked> findByWeekNumber(int weekNumber); List<HoursWorked> findByWeekNumber(int weekNumber);
List<HoursWorked> findByDate(LocalDate date);
} }

View File

@ -1,15 +1,11 @@
package com.primefactorsolutions.service; package com.primefactorsolutions.service;
import com.primefactorsolutions.model.Employee;
import com.primefactorsolutions.model.HoursWorked; import com.primefactorsolutions.model.HoursWorked;
import com.primefactorsolutions.repositories.HoursWorkedRepository; import com.primefactorsolutions.repositories.HoursWorkedRepository;
import org.apache.commons.beanutils.BeanComparator;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.time.LocalDate; import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
@Service @Service
public class HoursWorkedService { public class HoursWorkedService {
@ -24,12 +20,6 @@ public class HoursWorkedService {
return hoursWorkedRepository.findAll(); return hoursWorkedRepository.findAll();
} }
public HoursWorked findHoursWorked(final UUID id) {
Optional<HoursWorked> hoursWorked = hoursWorkedRepository.findById(id);
HoursWorked hw = hoursWorked.get();
return hw;
}
public HoursWorked saveHoursWorked(final HoursWorked hoursWorked) { public HoursWorked saveHoursWorked(final HoursWorked hoursWorked) {
return hoursWorkedRepository.save(hoursWorked); return hoursWorkedRepository.save(hoursWorked);
} }
@ -38,47 +28,13 @@ public class HoursWorkedService {
return hoursWorkedRepository.save(hoursWorked); return hoursWorkedRepository.save(hoursWorked);
} }
public void deleteHoursWorked(final Long id) {
hoursWorkedRepository.deleteById(id);
}
public List<HoursWorked> findByWeekNumber(final int weekNumber) { public List<HoursWorked> findByWeekNumber(final int weekNumber) {
return hoursWorkedRepository.findByWeekNumber(weekNumber); return hoursWorkedRepository.findByWeekNumber(weekNumber);
} }
public List<HoursWorked> findByDate(final LocalDate date) {
return hoursWorkedRepository.findByDate(date);
}
public List<HoursWorked> findByDateAndWeekNumber(final LocalDate date, final int weekNumber) {
return hoursWorkedRepository.findByDate(date);
}
public List<HoursWorked> findHoursWorkeds(
final int start, final int pageSize, final String sortProperty, final boolean asc) {
List<HoursWorked> 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<HoursWorked> findHoursWorkeds(final int start, final int pageSize) {
List<HoursWorked> hoursWorkeds = hoursWorkedRepository.findAll();
int end = Math.min(start + pageSize, hoursWorkeds.size());
return hoursWorkeds.subList(start, end);
}
public HoursWorked getHoursWorked(final UUID id) {
Optional<HoursWorked> registro = hoursWorkedRepository.findById(id);
HoursWorked hw = registro.orElse(null);
if (hw == null) {
System.out.println("No se encontró el registro de horas trabajadas");
return null;
}
return hw;
}
} }

View File

@ -56,6 +56,7 @@ public class EmployeeView extends BeanValidationForm<Employee> implements HasUrl
private final TimeOffRequestService requestService; private final TimeOffRequestService requestService;
private final TeamService teamService; private final TeamService teamService;
// TODO: campo usado para registrar al empleado en LDAP. Este campo podria estar en otro form eventualmente. // TODO: campo usado para registrar al empleado en LDAP. Este campo podria estar en otro form eventualmente.
private final TextField username = createTextField("Username: ", 30, true); private final TextField username = createTextField("Username: ", 30, true);
private final TextField firstName = createTextField("Nombres: ", 30, true); private final TextField firstName = createTextField("Nombres: ", 30, true);
@ -64,19 +65,24 @@ public class EmployeeView extends BeanValidationForm<Employee> implements HasUrl
private final ComboBox<Employee.Gender> gender = createGenderComboBox(); private final ComboBox<Employee.Gender> gender = createGenderComboBox();
private final VDatePicker birthday = new VDatePicker("Fecha de Nacimiento"); private final VDatePicker birthday = new VDatePicker("Fecha de Nacimiento");
private final TextField age = createTextField("Edad", 3, false); private final TextField age = createTextField("Edad", 3, false);
private final TextField birthCity = createTextField("Ciudad y País de Nacimiento ejemplo: (Ciudad, País) ", 30, false); private final TextField birthCity = createTextField("Ciudad y País de Nacimiento", 20, false);
private final TextField residenceAddress = createTextField("Dirección de Residencia", 50, false); private final TextField residenceAddress = createTextField("Dirección de Residencia", 50, false);
private final TextField localAddress = createTextField("Departamento y Provincia de Residencia ejemplo: (Departamento-Provincia)", 30, false); private final TextField localAddress = createTextField("Dep/Provincia de Residencia", 10, false);
private final ComboBox<Employee.MaritalStatus> maritalStatus = createMaritalStatusComboBox(); private final ComboBox<Employee.MaritalStatus> maritalStatus = createMaritalStatusComboBox();
private final TextField numberOfChildren = createTextField("Numero de Hijos", 2, false); private final TextField numberOfChildren = createTextField("Numero de Hijos", 3, false);
private final TextField ci = createTextField("CI", 10, false); private final TextField ci = createTextField("CI", 30, false);
private final TextField issuedIn = createTextField("Expedido en ", 10, false); private final TextField issuedIn = createTextField("Expedido en ", 30, false);
private final TextField phoneNumber = createTextField("Teléfono", 8, false); private final TextField phoneNumber = createTextField("Teléfono", 8, false);
private final EmailField personalEmail = createEmailField("E-mail ejemplo: (ejemplo@gmail.com)"); private final EmailField personalEmail = createEmailField("E-mail");
private final TextField cod = createTextField("Codigo de Empleado", 30, false);
private final TextField position = createTextField("Cargo", 30, false);
private final ComboBox<Team> team = new ComboBox<>("Equipo");
private final TextField leadManager = createTextField("Lead/Manager", 30, false);
private final TextField project = createTextField("Proyecto", 30, false);
private final TextField emergencyCName = createTextField("Nombres y Apellidos de Contacto", 50, false); private final TextField emergencyCName = createTextField("Nombres y Apellidos de Contacto", 50, false);
private final TextField emergencyCAddress = createTextField("Dirección de Contacto", 50, false); private final TextField emergencyCAddress = createTextField("Dirección de Contacto", 50, false);
private final TextField emergencyCPhone = createTextField("Teléfono de Contacto", 8, false); private final TextField emergencyCPhone = createTextField("Teléfono de Contacto", 8, false);
private final EmailField emergencyCEmail = createEmailField("Email de Contacto ejemplo: (ejemplo@gmail.com)"); private final EmailField emergencyCEmail = createEmailField("Email de Contacto");
private final MemoryBuffer buffer = new MemoryBuffer(); private final MemoryBuffer buffer = new MemoryBuffer();
private final Upload upload = new Upload(buffer); private final Upload upload = new Upload(buffer);
@ -95,15 +101,10 @@ public class EmployeeView extends BeanValidationForm<Employee> implements HasUrl
private final TextField certification4 = createTextField("Certificación 4", 30, false); private final TextField certification4 = createTextField("Certificación 4", 30, false);
private final TextField recognition = createTextField("Reconocimientos", 30, false); private final TextField recognition = createTextField("Reconocimientos", 30, false);
private final TextField achievements = createTextField("Logros Profesionales", 30, false); private final TextField achievements = createTextField("Logros Profesionales", 30, false);
private final TextField language = createTextField("Idioma", 50, false); private final TextField language = createTextField("Idioma", 30, false);
private final TextField languageLevel = createTextField("Nivel de Idioma", 30, false); private final TextField languageLevel = createTextField("Nivel de Idioma", 30, false);
//INFORMACION ADMINISTRATIVA //INFORMACION DE CONTRATACION
private final TextField cod = createTextField("Codigo de Empleado", 20, false);
private final TextField position = createTextField("Cargo", 30, false);
private final ComboBox<Team> team = new ComboBox<>("Equipo");
private final TextField leadManager = createTextField("Lead/Manager", 30, false);
private final TextField project = createTextField("Proyecto", 30, false);
private final VDatePicker dateOfEntry = new VDatePicker("Fecha de Ingreso"); private final VDatePicker dateOfEntry = new VDatePicker("Fecha de Ingreso");
private final VDatePicker dateOfExit = new VDatePicker("Fecha de Retiro"); private final VDatePicker dateOfExit = new VDatePicker("Fecha de Retiro");
private final TextField contractType = createTextField("Tipo de Contratación", 30, false); private final TextField contractType = createTextField("Tipo de Contratación", 30, false);
@ -140,7 +141,7 @@ public class EmployeeView extends BeanValidationForm<Employee> implements HasUrl
//TITULOS PARA INFORMACIÓN ADMINISTRATIVA //TITULOS PARA INFORMACIÓN ADMINISTRATIVA
private final H2 infoAdm = new H2("Información Administrativa"); private final H2 infoAdm = new H2("Información Administrativa");
private final H3 infoCont = new H3("Información de Contratación"); private final H3 infoCont = new H3("Información de Contratación");
private final H3 datBanc = new H3("Datos Bancarios"); private final H3 datBanc = new H3("Datos Bancados");
private final H3 datGest = new H3("Datos Gestora Pública y Seguro Social"); private final H3 datGest = new H3("Datos Gestora Pública y Seguro Social");
public EmployeeView(final EmployeeService employeeService, public EmployeeView(final EmployeeService employeeService,
@ -176,8 +177,6 @@ public class EmployeeView extends BeanValidationForm<Employee> implements HasUrl
reportButton.setVisible(true); reportButton.setVisible(true);
birthday.addValueChangeListener(event -> calculateAge()); birthday.addValueChangeListener(event -> calculateAge());
birthday.setMax(java.time.LocalDate.now()); birthday.setMax(java.time.LocalDate.now());
dateOfEntry.addValueChangeListener(event -> calculateSeniority());
dateOfEntry.addValueChangeListener(event -> calculateSeniority());
reportButton.addClickListener((ComponentEventListener<ClickEvent<Button>>) buttonClickEvent -> { reportButton.addClickListener((ComponentEventListener<ClickEvent<Button>>) buttonClickEvent -> {
var employee = getEntity(); var employee = getEntity();
@ -205,30 +204,10 @@ public class EmployeeView extends BeanValidationForm<Employee> implements HasUrl
int birthYear = birthday.getValue().getYear(); int birthYear = birthday.getValue().getYear();
int ages = currentYear - birthYear; int ages = currentYear - birthYear;
age.setValue(String.valueOf(ages)); age.setValue(String.valueOf(ages));
if (ages < 18) {
birthday.setInvalid(true);
birthday.setErrorMessage("La edad no puede ser menor a 18 años.");
Notification.show("La edad ingresada no es válida, debe ser mayor o igual a 18 años.");
} else {
birthday.setInvalid(false);
}
System.out.println(age); System.out.println(age);
} }
} }
private void calculateSeniority() {
LocalDate entryDate = dateOfEntry.getValue();
LocalDate exitDate = dateOfExit.getValue() != null ? dateOfExit.getValue() : LocalDate.now();
if (entryDate != null) {
long yearsOfService = ChronoUnit.YEARS.between(entryDate, exitDate);
String seniorityValue = yearsOfService + " años ";
seniority.setValue(seniorityValue);
} else {
seniority.setValue("No disponible");
}
}
private void configureUpload() { private void configureUpload() {
upload.setAcceptedFileTypes("image/jpeg", "image/png"); upload.setAcceptedFileTypes("image/jpeg", "image/png");
upload.setMaxFileSize(1024 * 1024); upload.setMaxFileSize(1024 * 1024);
@ -240,15 +219,11 @@ public class EmployeeView extends BeanValidationForm<Employee> implements HasUrl
getEntity().setProfileImage(base64Image); getEntity().setProfileImage(base64Image);
profileImagePreview.setSrc("data:image/png;base64," + base64Image); profileImagePreview.setSrc("data:image/jpeg;base64," + base64Image);
profileImagePreview.setMaxWidth("150px"); profileImagePreview.setMaxWidth("150px");
profileImagePreview.setMaxHeight("150px"); profileImagePreview.setMaxHeight("150px");
} catch (IOException e) { } catch (IOException e) {
Notification.show("Error al subir la imagen: " + e.getMessage()); Notification.show("Error al subir la imagen.");
e.printStackTrace();
} catch (Exception e) {
Notification.show("Error en el servidor al procesar la imagen.");
e.printStackTrace();
} }
}); });
} }
@ -419,12 +394,12 @@ public class EmployeeView extends BeanValidationForm<Employee> implements HasUrl
if (employee.getProfileImage() != null && !employee.getProfileImage().isEmpty()) { if (employee.getProfileImage() != null && !employee.getProfileImage().isEmpty()) {
profileImagePreview.setSrc("data:image/jpeg;base64," + employee.getProfileImage()); profileImagePreview.setSrc("data:image/jpeg;base64," + employee.getProfileImage());
profileImagePreview.setVisible(true); profileImagePreview.setVisible(true);
profileImagePreview.setMaxWidth("250px"); profileImagePreview.setMaxWidth("150px");
profileImagePreview.setMaxHeight("250px"); profileImagePreview.setMaxHeight("150px");
upload.setVisible(true); upload.setVisible(false);
} else { } else {
profileImagePreview.setVisible(true); profileImagePreview.setVisible(false);
upload.setVisible(true); upload.setVisible(true);
} }
} }
@ -504,7 +479,6 @@ public class EmployeeView extends BeanValidationForm<Employee> implements HasUrl
emergencyCPhone.setReadOnly(false); emergencyCPhone.setReadOnly(false);
emergencyCEmail.setReadOnly(false); emergencyCEmail.setReadOnly(false);
upload.setVisible(false); upload.setVisible(false);
profileImagePreview.setVisible(true);
age.setReadOnly(false); age.setReadOnly(false);
gender.setReadOnly(false); gender.setReadOnly(false);
status.setReadOnly(false); status.setReadOnly(false);
@ -552,6 +526,7 @@ public class EmployeeView extends BeanValidationForm<Employee> implements HasUrl
birthCity, residenceAddress, localAddress, birthCity, residenceAddress, localAddress,
maritalStatus, ci, issuedIn, numberOfChildren, maritalStatus, ci, issuedIn, numberOfChildren,
phoneNumber, personalEmail, phoneNumber, personalEmail,
cod, position, team, leadManager, project,
contEmerg, emergencyCName, emergencyCAddress, emergencyCPhone, emergencyCEmail, contEmerg, emergencyCName, emergencyCAddress, emergencyCPhone, emergencyCEmail,
infProf, infProf,
titulos, pTitle1, pTitle2, pTitle3, pStudy1, pStudy2, pStudy3, titulos, pTitle1, pTitle2, pTitle3, pStudy1, pStudy2, pStudy3,
@ -559,7 +534,6 @@ public class EmployeeView extends BeanValidationForm<Employee> implements HasUrl
logros, recognition, achievements, logros, recognition, achievements,
idioma, language, languageLevel, idioma, language, languageLevel,
infoAdm, infoAdm,
cod, position, team, leadManager, project,
infoCont, dateOfEntry, dateOfExit, contractType, seniority, salary, infoCont, dateOfEntry, dateOfExit, contractType, seniority, salary,
datBanc, bankName, accountNumber, datBanc, bankName, accountNumber,
datGest, gpss, sss, beneficiaries, datGest, gpss, sss, beneficiaries,

View File

@ -1,101 +0,0 @@
package com.primefactorsolutions.views;
import com.primefactorsolutions.model.HoursWorked;
import com.primefactorsolutions.service.HoursWorkedService;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.grid.GridSortOrder;
import com.vaadin.flow.component.html.H2;
import com.vaadin.flow.component.html.Main;
import com.vaadin.flow.data.provider.SortDirection;
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;
import org.vaadin.firitin.components.grid.PagingGrid;
import java.util.List;
@SpringComponent
@PermitAll
@Scope("prototype")
@PageTitle("HoursWorkedList")
@Route(value = "/hours-worked-list", layout = MainLayout.class)
public class HoursWorkedListView extends Main {
private final HoursWorkedService hoursWorkedService;
private final PagingGrid<HoursWorked> table = new PagingGrid<>(HoursWorked.class);
public HoursWorkedListView (final HoursWorkedService hoursWorkedService) {
this.hoursWorkedService = hoursWorkedService;
setupView();
refreshGrid();
}
private void setupView() {
add(new H2("Lista de Horas trabajadas"));
configureTable();
add(createAddHoursWorkedButton());
add(table);
}
private void configureTable() {
table.setColumns("Actividad", "Lunes", "Martes", "Miercoles", "Jueves", "Viernes", "Sabado", "Domingo");
addEditButtonColumn("View", this::navigateToHoursWorkedView);
addEditButtonColumn("Edit", this::navigateToEditView);
setupPagingGrid();
}
private void addEditButtonColumn( final String label, final ButtonClickHandler handler) {
table.addComponentColumn(hoursWorked -> createButton(label, () -> handler.handle(hoursWorked)));
}
private Button createButton(final String label, final Runnable onClickAction) {
Button button = new Button(label);
button.addClickListener(event -> onClickAction.run());
return button;
}
private Button createAddHoursWorkedButton() { return createButton("Crear Actividad", this::navigateToAddHoursWorkedView);}
private void navigateToEditView(final HoursWorked hoursWorked) {
getUI().ifPresent(ui -> ui.navigate(HoursWorkedView.class, hoursWorked.getId().toString() + "/edit"));
}
private void navigateToHoursWorkedView(final HoursWorked hoursWorked) {
getUI().ifPresent(ui -> ui.navigate(HoursWorkedView.class, hoursWorked.getId().toString() + "/view"));
}
private void navigateToAddHoursWorkedView() { getUI().ifPresent(ui -> ui.navigate(HoursWorkedView.class, "new"));}
private void setupPagingGrid() {
table.setPaginationBarMode(PagingGrid.PaginationBarMode.BOTTOM);
table.setPageSize(5);
}
private void refreshGrid() {
table.setPagingDataProvider((page, pageSize) -> fetchHoursWorkeds((int) page, pageSize));
}
private List<HoursWorked> fetchHoursWorkeds(final int page, final int pageSize) {
int start = page * pageSize;
if (hasSortOrder()) {
return fetchSortedHoursWorkeds(start, pageSize);
}
return hoursWorkedService.findHoursWorkeds(start, pageSize);
}
private boolean hasSortOrder() { return !table.getSortOrder().isEmpty(); }
private List<HoursWorked> fetchSortedHoursWorkeds(final int start, final int pageSize) {
GridSortOrder<HoursWorked> sortOrder = table.getSortOrder().getFirst();
return hoursWorkedService.findHoursWorkeds(start, pageSize,
sortOrder.getSorted().getKey(),
sortOrder.getDirection() == SortDirection.ASCENDING);
}
@FunctionalInterface
private interface ButtonClickHandler {
void handle(HoursWorked hoursWorked);
}
}

View File

@ -1,164 +1,477 @@
package com.primefactorsolutions.views; package com.primefactorsolutions.views;
import com.primefactorsolutions.model.Actividad;
import com.primefactorsolutions.model.Employee; import com.primefactorsolutions.model.Employee;
import com.primefactorsolutions.model.HoursWorked; import com.primefactorsolutions.model.HoursWorked;
import com.primefactorsolutions.model.Team;
import com.primefactorsolutions.service.EmployeeService; import com.primefactorsolutions.service.EmployeeService;
import com.primefactorsolutions.service.HoursWorkedService; import com.primefactorsolutions.service.HoursWorkedService;
import com.primefactorsolutions.service.TeamService; import com.vaadin.flow.component.grid.Grid;
import com.primefactorsolutions.service.TimeOffRequestService; import com.vaadin.flow.component.html.H2;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.datepicker.DatePicker;
import com.vaadin.flow.component.html.H3;
import com.vaadin.flow.component.notification.Notification; import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.component.textfield.TextField;
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.router.*; import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.spring.annotation.SpringComponent; import com.vaadin.flow.spring.annotation.SpringComponent;
import jakarta.annotation.security.PermitAll; import jakarta.annotation.security.PermitAll;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.Scope;
import org.vaadin.firitin.form.BeanValidationForm; import com.vaadin.flow.component.html.Label;
import org.vaadin.firitin.components.datepicker.VDatePicker;
import java.awt.*;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.IsoFields;
import java.time.temporal.WeekFields;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.Locale;
@SpringComponent @SpringComponent
@PermitAll @PermitAll
@Scope("prototype") @Scope("prototype")
@PageTitle("Horas Trabajadas") @PageTitle("Horas Trabajadas")
@Route(value = "/timesheets/listhw/:hours-worked?/me", layout = MainLayout.class) @Route(value = "/hours-worked/me", layout = MainLayout.class)
public class HoursWorkedView extends BeanValidationForm<HoursWorked> implements HasUrlParameter<String> { public class HoursWorkedView extends VerticalLayout {
private final DatePicker dateField = new DatePicker("Fecha"); private final List<Actividad> actividades = new ArrayList<>();
private final ComboBox<Team> teamField = new ComboBox<>("Equipo"); private final List<Actividad> actividadesEspecificas = new ArrayList<>(); // Nueva lista para tareas específicas
private final ComboBox<Employee> employeeField = new ComboBox<>("Empleado"); private final Grid<Actividad> grid = new Grid<>(Actividad.class);
private final TextField activityField = new TextField("Actividad"); private final Grid<Actividad> gridActividadesEspecificas = new Grid<>(Actividad.class);
private final TextField hoursField = new TextField("Horas");
private final HoursWorkedService hoursWorkedService; private final ComboBox<Employee> employeeComboBox = new ComboBox<>("Empleado");
private final ComboBox<String> equipoDropdown = new ComboBox<>("Equipo");
private VDatePicker fechaPicker = new VDatePicker("Selecciona una fecha");
private final ComboBox<String> tareasEspecificasDropdown = new ComboBox<>("Tareas Específicas");
private final TextField tareaEspecificaInput = new TextField("Especificar Tarea");
private TextField horasTareaInput = crearCampoHora("Horas Tareas");
private LocalDate selectedStartOfWeek;
private int weekNumber;
@Autowired
private final EmployeeService employeeService; private final EmployeeService employeeService;
private final TeamService teamService; @Autowired
private HoursWorked request; private final HoursWorkedService hoursWorkedService;
private Employee employee;
private Button saveButton; 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 Label horasPendientesLabel = new Label();
public HoursWorkedView(HoursWorkedService hoursWorkedService, public HoursWorkedView(final EmployeeService employeeService, final HoursWorkedService hoursWorkedService) {
EmployeeService employeeService,
TeamService teamService, TimeOffRequestService timeOffRequestService) {
super(HoursWorked.class);
this.hoursWorkedService = hoursWorkedService;
this.employeeService = employeeService; this.employeeService = employeeService;
this.teamService = teamService; this.hoursWorkedService = hoursWorkedService;
configurarVista();
// Initialize combo boxes configurarGrid();
initializeTeamField(); configurarGridActividadesEspecificas();
initializeEmployeeField(); cargarDatos();
configurarTareasEspecificas();
} }
@Override private void configurarTareasEspecificas() {
public void setParameter(BeforeEvent beforeEvent, final String action) { tareasEspecificasDropdown.setItems("Entrevistas", "Reuniones", "Colaboraciones",
final RouteParameters params = beforeEvent.getRouteParameters(); "Aprendizajes", "Proyectos PFS", "Otros");
final String s = params.get("hours-workedId").orElse(null); tareasEspecificasDropdown.setPlaceholder("Selecciona una tarea...");
if ("new".equals(action)) { tareasEspecificasDropdown.addValueChangeListener(event -> {
setEntityWithEnabledSave(new HoursWorked()); String selected = event.getValue();
} else { // Activa el campo de texto si la opción seleccionada es "Otros"
UUID hoursWorkedId = UUID.fromString(s); tareaEspecificaInput.setVisible("Otros".equals(selected));
var hoursWorked = hoursWorkedService.getHoursWorked(hoursWorkedId); if (!"Otros".equals(selected)) {
setEntityWithEnabledSave(hoursWorked); tareaEspecificaInput.clear();
if ("edit".equals(action) && !s.isEmpty()) {
saveButton.setVisible(true);
} else if ("view".equals(action) && !s.isEmpty()) {
saveButton.setVisible(false);
} }
});
tareaEspecificaInput.setVisible(false);
}
private void cargarDatos() {
if (selectedStartOfWeek != null && weekNumber > 0) {
List<HoursWorked> listaDeHorasTrabajadas = obtenerDatos();
for (HoursWorked hours : listaDeHorasTrabajadas) {
LocalDate activityDate = hours.getFecha();
int activityWeek = getWeekOfYear(activityDate);
if (activityWeek == weekNumber) {
Actividad actividad = hours.getActividad();
if (actividad != null) {
DayOfWeek dayOfWeek = activityDate.getDayOfWeek();
agregarOActualizarActividad(actividad, dayOfWeek, hours.getTotalHours());
}
}
}
grid.setItems(actividades);
gridActividadesEspecificas.setItems(actividadesEspecificas);
calcularTotalHoras(listaDeHorasTrabajadas);
} }
} }
@Override private void setEmployeeComboBoxProperties() {
protected List<Component> getFormComponents() { employeeComboBox.setWidth("250px");
return List.of( employeeComboBox.setPlaceholder("Buscar empleado...");
dateField, employeeComboBox.setItems(employeeService.findAllEmployees());
teamField, employeeComboBox.setItemLabelGenerator(employee -> employee.getFirstName() + " " + employee.getLastName());
employeeField, employeeComboBox.setAllowCustomValue(false);
activityField, employeeComboBox.addCustomValueSetListener(event ->
hoursField, Notification.show("Selecciona un empleado válido de la lista.")
createCloseButton()
); );
}
protected Button createSaveButton() { employeeComboBox.addValueChangeListener(event -> {
saveButton = new Button("Guardar"); Employee selectedEmployee = event.getValue();
saveButton.addClickListener(event -> saveHoursWorked()); if (selectedEmployee != null) {
return saveButton; Notification.show("Empleado seleccionado: "
} + selectedEmployee.getFirstName() + " "
+ selectedEmployee.getLastName());
protected Button createCloseButton() { }
Button closeButton = new Button("Cerrar");
closeButton.addClickListener(event -> closeForm());
return closeButton;
}
private void initializeTeamField() {
teamField.setItems(teamService.findAllTeams());
teamField.setItemLabelGenerator(Team::getName);
teamField.addValueChangeListener(event -> {
teamField.getValue();
}); });
} }
private void initializeEmployeeField() { private int getWeekOfYear(final LocalDate date) {
employeeField.setItems(employeeService.findAllEmployees()); return date.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR);
employeeField.setItemLabelGenerator(employee -> employee.getFirstName() + " " + employee.getLastName());
} }
private void saveHoursWorked() { private void configurarVista() {
if (isFormValid()) { fechaPicker.setMax(LocalDate.now());
HoursWorked hoursWorked = getEntity(); fechaPicker.addValueChangeListener(event -> {
setFieldValues(hoursWorked); LocalDate selectedDate = event.getValue();
if (selectedDate != null) {
selectedStartOfWeek = getStartOfWeek(selectedDate);
weekNumber = getWeekOfYear(selectedDate);
cargarDatos();
}
});
Button verMesButton = new Button("Ver Mes", event -> {
getUI().ifPresent(ui -> ui.navigate(HoursWorkedMonthView.class));
});
equipoDropdown.setItems("ABC", "DEF", "XYZ");
equipoDropdown.setWidth("250px");
equipoDropdown.addValueChangeListener(event -> {
String selectedEquipo = event.getValue();
if (selectedEquipo != null) {
// Filtra la lista de empleados según el equipo seleccionado
List<Employee> filteredEmployees = employeeService.findEmployeesByTeam(selectedEquipo);
employeeComboBox.setItems(filteredEmployees);
}
});
setEmployeeComboBoxProperties();
HorizontalLayout filtersLayout = new HorizontalLayout(equipoDropdown, employeeComboBox);
filtersLayout.setSpacing(true);
HorizontalLayout actividadFormLayout = configurarFormularioActividades();
HorizontalLayout tareasEspecificasLayout = configurarTareasEspecificasLayout();
Button actualizarButton = new Button("Actualizar Totales", event -> actualizarTotales());
Button guardarButton = new Button("Guardar", event -> guardarActividades());
Button cerrarButton = new Button("Cerrar", event -> this.closeView());
HorizontalLayout buttonsLayout = new HorizontalLayout(actualizarButton, guardarButton,
cerrarButton, verMesButton);
VerticalLayout totalesLayout = new VerticalLayout(totalCompletadoLabel,
horasPendientesLabel);
totalesLayout.setSpacing(true);
totalesLayout.setPadding(true);
add(fechaPicker, filtersLayout, actividadFormLayout,
equipoLabel, grid, empresaLabel, tareasEspecificasLayout,
gridActividadesEspecificas, buttonsLayout, totalesLayout);
}
private void configurarGrid() {
grid.removeAllColumns();
grid.setItems(actividades);
grid.addColumn(Actividad::getNombre).setHeader("Actividad");
grid.addColumn(Actividad::getLunes).setHeader("Lunes");
grid.addColumn(Actividad::getMartes).setHeader("Martes");
grid.addColumn(Actividad::getMiercoles).setHeader("Miércoles");
grid.addColumn(Actividad::getJueves).setHeader("Jueves");
grid.addColumn(Actividad::getViernes).setHeader("Viernes");
grid.addColumn(Actividad::getSabado).setHeader("Sábado");
grid.addColumn(Actividad::getDomingo).setHeader("Domingo");
grid.addColumn(this::calcularTotalPorDia).setHeader("Total Día").setKey("totalDia");
grid.setItems(actividades);
}
private void configurarGridActividadesEspecificas() {
gridActividadesEspecificas.removeAllColumns();
gridActividadesEspecificas.setItems(actividadesEspecificas);
gridActividadesEspecificas.addColumn(Actividad::getTarea).setHeader("Actividad");
gridActividadesEspecificas.addColumn(Actividad::getLunes).setHeader("Lunes");
gridActividadesEspecificas.addColumn(Actividad::getMartes).setHeader("Martes");
gridActividadesEspecificas.addColumn(Actividad::getMiercoles).setHeader("Miércoles");
gridActividadesEspecificas.addColumn(Actividad::getJueves).setHeader("Jueves");
gridActividadesEspecificas.addColumn(Actividad::getViernes).setHeader("Viernes");
gridActividadesEspecificas.addColumn(Actividad::getSabado).setHeader("Sábado");
gridActividadesEspecificas.addColumn(Actividad::getDomingo).setHeader("Domingo");
gridActividadesEspecificas.addColumn(this::calcularTotalPorDia).setHeader("Total Día Específico")
.setKey("totalDiaEspecifico");
}
private HorizontalLayout configurarFormularioActividades() {
TextField actividadNombre = new TextField("Actividad");
actividadNombre.setWidth("200px");
TextField horasInput = crearCampoHora("Horas");
Button agregarActividadButton = new Button("Agregar Actividad", e -> {
try {
LocalDate selectedDate = fechaPicker.getValue();
if (selectedDate == null) {
Notification.show("Por favor, selecciona una fecha.");
return;
}
int selectedWeekNumber = getWeekOfYear(selectedDate);
if (selectedWeekNumber != weekNumber) {
Notification.show("Solo puedes agregar actividades dentro de la semana actual.");
return;
}
DayOfWeek selectedDay = selectedDate.getDayOfWeek();
Actividad.Builder actividadBuilder = new Actividad.Builder()
.nombre(actividadNombre.getValue());
double horas = parseHoras(horasInput.getValue());
switch (selectedDay) {
case MONDAY -> actividadBuilder.lunes(horas);
case TUESDAY -> actividadBuilder.martes(horas);
case WEDNESDAY -> actividadBuilder.miercoles(horas);
case THURSDAY -> actividadBuilder.jueves(horas);
case FRIDAY -> actividadBuilder.viernes(horas);
case SATURDAY -> actividadBuilder.sabado(horas);
case SUNDAY -> actividadBuilder.domingo(horas);
default -> throw new IllegalArgumentException("Día seleccionado no válido: " + selectedDay);
}
String tareaSeleccionada = tareasEspecificasDropdown.getValue();
double horasTarea = parseHoras(horasTareaInput.getValue());
if (tareaSeleccionada != null && !tareaSeleccionada.isEmpty()) {
actividadBuilder.tarea(tareaSeleccionada).lunes(horasTarea);
Actividad nuevaActividadEspecifica = actividadBuilder.build();
actividadesEspecificas.add(nuevaActividadEspecifica);
gridActividadesEspecificas.setItems(actividadesEspecificas);
} else {
Actividad nuevaActividad = actividadBuilder.build();
actividades.add(nuevaActividad);
grid.setItems(actividades);
}
Actividad nuevaActividad = actividadBuilder.build();
agregarOActualizarActividad(nuevaActividad, selectedDay, horas);
actualizarTotales();
Notification.show("Actividad agregada correctamente");
actividadNombre.clear();
horasInput.clear();
tareasEspecificasDropdown.clear();
horasTareaInput.clear();
} catch (NumberFormatException ex) {
Notification.show("Error: Por favor ingresa números válidos para las horas.");
}
});
return new HorizontalLayout(actividadNombre, horasInput, agregarActividadButton);
}
private void agregarOActualizarActividad(final Actividad nuevaActividad, final DayOfWeek dia, final double horas) {
Actividad actividadExistente = actividades.stream()
.filter(a -> a.getNombre().equals(nuevaActividad.getNombre()))
.findFirst()
.orElse(null);
if (actividadExistente != null) {
// Si la actividad ya existe, actualiza las horas para el día correspondiente
switch (dia) {
case MONDAY -> actividadExistente.setLunes(horas);
case TUESDAY -> actividadExistente.setMartes(horas);
case WEDNESDAY -> actividadExistente.setMiercoles(horas);
case THURSDAY -> actividadExistente.setJueves(horas);
case FRIDAY -> actividadExistente.setViernes(horas);
case SATURDAY -> actividadExistente.setSabado(horas);
case SUNDAY -> actividadExistente.setDomingo(horas);
default -> throw new IllegalArgumentException("Día seleccionado no válido: " + dia);
}
} else {
switch (dia) {
case MONDAY -> nuevaActividad.setLunes(horas);
case TUESDAY -> nuevaActividad.setMartes(horas);
case WEDNESDAY -> nuevaActividad.setMiercoles(horas);
case THURSDAY -> nuevaActividad.setJueves(horas);
case FRIDAY -> nuevaActividad.setViernes(horas);
case SATURDAY -> nuevaActividad.setSabado(horas);
case SUNDAY -> nuevaActividad.setDomingo(horas);
default -> throw new IllegalArgumentException("Día seleccionado no válido: " + dia);
}
actividades.add(nuevaActividad);
}
grid.setItems(actividades);
guardarActividades();
}
private HorizontalLayout configurarTareasEspecificasLayout() {
Button agregarTareaButton = new Button("Agregar Tarea PFS", e -> {
try {
String tareaSeleccionada = tareasEspecificasDropdown.getValue();
String tareaNombre = "Otros"
.equals(tareaSeleccionada) ? tareaEspecificaInput
.getValue() : tareaSeleccionada;
if (tareaNombre == null || tareaNombre.isEmpty()) {
Notification.show("Por favor, especifica la tarea.");
return;
}
double horasTarea = parseHoras(horasTareaInput.getValue());
if (horasTarea <= 0) {
Notification.show("Por favor, ingresa un número válido para las horas.");
return;
}
if (tareaSeleccionada != null && !tareaSeleccionada.isEmpty() && horasTarea > 0) {
LocalDate selectedDate = fechaPicker.getValue();
if (selectedDate == null) {
Notification.show("Selecciona una fecha para asignar la tarea.");
return;
}
DayOfWeek selectedDay = selectedDate.getDayOfWeek();
Actividad.Builder actividadBuilder = new Actividad.Builder().tarea(tareaNombre);
switch (selectedDay) {
case MONDAY -> actividadBuilder.lunes(horasTarea);
case TUESDAY -> actividadBuilder.martes(horasTarea);
case WEDNESDAY -> actividadBuilder.miercoles(horasTarea);
case THURSDAY -> actividadBuilder.jueves(horasTarea);
case FRIDAY -> actividadBuilder.viernes(horasTarea);
case SATURDAY -> actividadBuilder.sabado(horasTarea);
case SUNDAY -> actividadBuilder.domingo(horasTarea);
default -> throw new IllegalArgumentException("Día seleccionado no válido: " + selectedDay);
}
Actividad nuevaActividadEspecifica = actividadBuilder.build();
actividadesEspecificas.add(nuevaActividadEspecifica);
gridActividadesEspecificas.setItems(actividadesEspecificas);
actualizarTotales();
tareasEspecificasDropdown.clear();
tareaEspecificaInput.clear();
horasTareaInput.clear();
Notification.show("Tarea específica agregada correctamente");
} else {
Notification.show("Selecciona una tarea y asegúrate de ingresar horas válidas.");
}
} catch (NumberFormatException ex) {
Notification.show("Error: Por favor ingresa un número válido para las horas.");
}
});
HorizontalLayout layout = new HorizontalLayout(tareasEspecificasDropdown,
tareaEspecificaInput, horasTareaInput, agregarTareaButton);
layout.setSpacing(true);
return layout;
}
private TextField crearCampoHora(final String placeholder) {
TextField field = new TextField(placeholder);
field.setWidth("80px");
field.setPlaceholder("0.0");
return field;
}
private double parseHoras(final String value) {
if (value == null || value.trim().isEmpty()) {
return 0.0;
}
return Double.parseDouble(value);
}
private LocalDate getStartOfWeek(final LocalDate date) {
WeekFields weekFields = WeekFields.of(Locale.getDefault());
return date.with(weekFields.dayOfWeek(), DayOfWeek.FRIDAY.getValue());
}
private double calcularTotalPorDia(final Actividad actividad) {
return actividad.getLunes() + actividad.getMartes() + actividad.getMiercoles()
+ actividad.getJueves() + actividad.getViernes() + actividad.getSabado() + actividad.getDomingo();
}
private void actualizarTotales() {
double totalActividadesGenerales = actividades.stream()
.mapToDouble(this::calcularTotalPorDia)
.sum();
double totalActividadesEspecificas = actividadesEspecificas.stream()
.mapToDouble(this::calcularTotalPorDia)
.sum();
double totalFinal = totalActividadesGenerales + totalActividadesEspecificas;
double horasPendientes = 40 - totalFinal;
totalCompletadoLabel.setText("Total Hrs/Semana Completadas: " + totalFinal);
horasPendientesLabel.setText("Horas Pendientes: " + horasPendientes);
}
private void guardarActividades() {
Employee selectedEmployee = employeeComboBox.getValue();
String selectedEquipo = equipoDropdown.getValue();
if (selectedEmployee == null || selectedEquipo == null) {
Notification.show("Por favor selecciona un equipo y un empleado.");
return;
}
if (actividades.isEmpty()) {
Notification.show("No hay actividades para guardar.");
return;
}
double totalHorasSemana = actividades.stream()
.mapToDouble(this::calcularTotalPorDia)
.sum();
List<HoursWorked> savedHoursWorked = new ArrayList<>(); // Para almacenar los objetos guardados
actividades.forEach(actividad -> {
HoursWorked hoursWorked = new HoursWorked();
hoursWorked.setActividad(actividad);
hoursWorked.setFecha(fechaPicker.getValue());
hoursWorked.setEmployee(selectedEmployee);
hoursWorked.setWeekNumber(weekNumber);
hoursWorked.setTotalHours(totalHorasSemana);
hoursWorkedService.saveHoursWorked(hoursWorked); hoursWorkedService.saveHoursWorked(hoursWorked);
Notification.show("Horas trabajadas guardadas correctamente.");
closeForm(); });
} Notification.show("Actividades guardadas correctamente.");
} }
private void setFieldValues(HoursWorked hoursWorked) { private double calcularTotalHoras(final List<HoursWorked> listaDeHorasTrabajadas) {
hoursWorked.setDate(dateField.getValue()); return listaDeHorasTrabajadas.stream()
hoursWorked.setTeam(teamField.getValue()); .mapToDouble(HoursWorked::getTotalHours)
hoursWorked.setEmployee(employeeField.getValue()); .sum();
hoursWorked.setActividad(activityField.getValue());
//hoursWorked.setHours(hoursField.;
} }
private void closeForm() { private List<HoursWorked> obtenerDatos() {
getUI().ifPresent(ui -> ui.navigate("hours-workedId")); return new ArrayList<>();
} }
private boolean isFormValid() { private void closeView() {
return dateField.getValue() != null && getUI().ifPresent(ui -> ui.navigate(HoursWorkedView.class));
teamField.getValue() != null &&
employeeField.getValue() != null &&
!activityField.isEmpty();
} }
private void configureViewOrEditAction(String action) {
if ("edit".equals(action) && request != null) {
setFieldsReadOnly(false);
} else if ("view".equals(action) && request != null) {
setFieldsReadOnly(true);
saveButton.setEnabled(false);
}
}
private void setFieldsReadOnly(boolean readOnly) {
dateField.setReadOnly(readOnly);
teamField.setReadOnly(readOnly);
employeeField.setReadOnly(readOnly);
activityField.setReadOnly(readOnly);
}
private H3 createEmployeeHeader() {
return new H3("Empleado: " + (employee != null ? employee.getFirstName() + " " + employee.getLastName() : ""));}
} }

View File

@ -150,7 +150,7 @@ public class MainLayout extends AppLayout {
LineAwesomeIcon.LIST_ALT.create())); LineAwesomeIcon.LIST_ALT.create()));
SideNavItem timesheet = new SideNavItem("My Timesheet", TimesheetView.class, SideNavItem timesheet = new SideNavItem("My Timesheet", TimesheetView.class,
LineAwesomeIcon.HOURGLASS_START_SOLID.create()); LineAwesomeIcon.HOURGLASS_START_SOLID.create());
timesheet.addItem(new SideNavItem("Hours Worked List View", HoursWorkedListView.class, timesheet.addItem(new SideNavItem("Horas Trabajadas", HoursWorkedView.class,
LineAwesomeIcon.ID_CARD_SOLID.create())); LineAwesomeIcon.ID_CARD_SOLID.create()));
timesheet.addItem(new SideNavItem("Reporte Horas Trabajadas", ReporteView.class, timesheet.addItem(new SideNavItem("Reporte Horas Trabajadas", ReporteView.class,
LineAwesomeIcon.ID_CARD_SOLID.create())); LineAwesomeIcon.ID_CARD_SOLID.create()));

View File

@ -10,7 +10,7 @@ import org.springframework.context.annotation.Scope;
@SpringComponent @SpringComponent
@Scope("prototype") @Scope("prototype")
@PageTitle("Timesheets") @PageTitle("Timesheets")
@Route(value = "/timesheets-report", layout = MainLayout.class) @Route(value = "/timesheets", layout = MainLayout.class)
@PermitAll @PermitAll
public class TimesheestReportView extends Main { public class TimesheestReportView extends Main {
} }

View File

@ -11,7 +11,7 @@ import org.springframework.context.annotation.Scope;
@PermitAll @PermitAll
@Scope("prototype") @Scope("prototype")
@PageTitle("Timesheet") @PageTitle("Timesheet")
@Route(value = "/timesheets", layout = MainLayout.class) @Route(value = "/timesheets/me", layout = MainLayout.class)
public class TimesheetView extends Main { public class TimesheetView extends Main {
} }