<repo_name>DarwinGonzalez/JPA-example<file_sep>/src/es/uv/prnr/p2/ProjectService.java
package es.uv.prnr.p2;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.persistence.*;


public class ProjectService {
	EntityManagerFactory emf;
	EntityManager em;
	
	public ProjectService() {
		this.emf = Persistence.createEntityManagerFactory("acmeEmployees");
		this.em = emf.createEntityManager();
	}
	
	/**
	 * Busca un departamento
	 * @param id identificador del departamento	
	 * @return entidad con el deparamenteo encontrado
	 */
	public Department getDepartmentById (String id) {
		return em.find(Department.class, id);
	}
	
	/**
	 * Asciende a un empleado a manager. Utilizar una estrateg�a de herencia adecuada
	 * en employee. Tened en cuenta que NO puede haber dos entidades con el mismo id
	 * por lo que habr� que eliminar el empleado original en algun momento.
	 * @param employeeId
	 * @param bonus
	 * @return
	 */
	public Manager promoteToManager(int employeeId, long bonus) {
		em.getTransaction().begin();
		Employee employee = em.find(Employee.class, employeeId);
		Manager man = new Manager(employee, bonus);	
		em.remove(employee);
		em.persist(man);
		em.getTransaction().commit();
		
		return man;
	}
	
	/**
	 * Crea un nuevo proyecto en el area de Big Data que comienza en la fecha actual y que finaliza
	 * en 3 a�os.
	 * @param name 
	 * @param d departamento asignado al proyecto
	 * @param m manager que asignado al proyecto
	 * @param budget
	 * @return el proyecto creado
	 */
	public Project createBigDataProject(String name, Department d, Manager m, BigDecimal budget) {
		em.getTransaction().begin();
		Project project = new Project(name, d, m,budget,LocalDate.now(),LocalDate.now().plusYears(3),"BigData");
		em.persist(project);
		em.getTransaction().commit();
		return project;
	}
	
	/**
	 * Crea un equipo de proyecto. Se debera implementa el m�todo addEmployee de 
	 * Project para incluir los empleados
	 * @param p proyecto al cual asignar el equipo
	 * @param startId identificador a partir del cual se asignan empleado
	 * @param endId identificador final de empleados. Se asume que start id < endId
	 */
	public void assignTeam (Project p, int startId, int endId) {
		em.getTransaction().begin();
		for(int i = startId; i <= endId; i++) {
			if(em.find(Employee.class, i) != null) {
				p.addEmployee(em.find(Employee.class, i));
			}
		}
		em.merge(p);
		em.getTransaction().commit();
	}
	
	/** 
	 * Genera un conjunto de horas inicial para cada empleado. El m�todo asigna para cada
	 * mes de duraci�n del proyecto, un n�mero entre 10-165 de horas a cada empleado.
	 * @param projectId
	 * @return total de horas generadas para el proyecto
	 */
	public int assignInitialHours (int projectId) {
		em.getTransaction().begin();
		int totalHours = 0;
		Project p = em.find(Project.class, projectId);
		LocalDate start = p.getStartDate();
		while (start.isBefore(p.getEndDate())) {
			for (Employee e: p.getEmployees()) {
				int hours = new Random().nextInt(165) + 10; 
				totalHours += hours;
				p.addHours(e, start.getMonthValue(), start.getYear(), hours);			
			}
			start = start.plusMonths(1);
		}

		em.persist(p);
		em.getTransaction().commit();
		return totalHours;
	}
	
	/**
	 * Busca si un empleado se encuentra asignado en el proyecto utilizando la
	 * namedQuery Project.findEmployee
	 * @param projectId
	 * @param firstName
	 * @param lastName
	 * @return cierto si se encuentra asignado al proyecto
	 */
	public boolean employeeInProject (int projectId, String firstName, String lastName){
		Query consulta= em.createNamedQuery("Project.findEmployee", Integer.class);
		consulta.setParameter("idProyecto", projectId);
		consulta.setParameter("nombre", firstName);
		consulta.setParameter("apellido", lastName);
		@SuppressWarnings("unchecked")
		List<Integer> lista= consulta.getResultList();
		if (lista.size() == 0) {
			return false;
		} else {
			return true;			
		}
	}
	
	/**
	 * Devuelve los meses con mayor n�mero de horas de un a�o determinado
	 * utilizando la namedQuery Project.getTopMonths
	 * @param projectId
	 * @param year a�o a seleccionar
	 * @param rank n�mero de meses a mostrar, se asume que rank <= 12
	 * @return una lista de objetos mes,hora ordenados de mayor a menor
	 */
	public List getTopHourMonths(int projectId, int year, int rank) {
//		Query consulta= em.createNamedQuery("Project.getTopMonths");
//		consulta.setParameter("idProyecto", projectId);
//		consulta.setParameter("año", year);
//		consulta.setMaxResults(rank);

		return  em.createNamedQuery("Project.getTopMonths").setParameter("idProyecto", projectId).setParameter("año", year).setMaxResults(rank).getResultList();
	}
	
	/**
	 * Devuelve para cada par mes-a�o el presupuesto teniendo en cuenta el 
	 * coste/hora de los empleados asociado utilizando la namedQuery Project.getMonthlyBudget
	 * que realiza una consulta nativa
	 * @param projectId
	 * @return una colecci�n de objetos MonthlyBudget
	 */
	public List<MonthlyBudget> getMonthlyBudget (int projectId){
		return em.createNamedQuery("Project.getMonthlyBudget", MonthlyBudget.class).setParameter("idProyecto", projectId)
				.getResultList();
	}
	
}
<file_sep>/src/es/uv/prnr/p2/Project.java
package es.uv.prnr.p2;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.*;


//TODO JPQL de Ejercicio3 employeeInProject 

@NamedQuery(name = "Project.findEmployee", 
			query = "select e.id from Employee e inner join e.assignedTo aT where e.firstName like :nombre and e.last_name like :apellido and aT.id = :idProyecto")

//TODO JPQL de Ejercicio3 getTopHoursMonth
@NamedQuery(
			name="Project.getTopMonths",
			query="select ph.month, max(ph.hours) as top from ProjectHours ph WHERE ph.year = :año and ph.project.id = :idProyecto group by ph.month order by top"
)

@NamedNativeQuery(name = "Project.getMonthlyBudget", query = "select mh.year, mh.month, sum(round(((s.salary/1650)*mh.hours),0)) as amount from monthly_hours mh "
		+ " inner join employees e on e.emp_no = mh.fk_employee"
		+ " inner join salaries s on s.emp_no = mh.fk_employee and s.to_date = '9999-01-01'"
		+ " where mh.fk_project = :idProyecto" + " group by mh.month, mh.year"
		+ " order by mh.year, mh.month", resultSetMapping = "MonthBudgetMapping")

// Mapeo del ResultSet para la consulta anterior
@SqlResultSetMapping(name = "MonthBudgetMapping", classes = {
		@ConstructorResult(targetClass = MonthlyBudget.class, columns = { @ColumnResult(name = "year"),
				@ColumnResult(name = "month"), @ColumnResult(name = "amount", type = Float.class) }) })

@Entity
@Table(name="project")
public class Project  {
	
	@Id @Column(name="id")
	private int id;

	@Column(name = "name", unique = false,
			nullable = false, length = 45)
	private String name;
	

	@ManyToOne
	@JoinColumn(name="fk_department")
	private Department department;

	@Column(name = "budget", unique = false,
			nullable = false, length = 10, scale = 2)
	private BigDecimal budget;
	
	@Column(name="start_date")
	private LocalDate startDate;
	
	@Column(name="end_date")
	private LocalDate endDate;
	
	@Column(name="area")
	private String area;
	
	@ManyToOne
	@JoinColumn(name="fk_manager")
	private Manager manager;
	
	@ManyToMany
	@JoinTable(
		name="project_team",
			joinColumns=@JoinColumn(name="project_id",
			referencedColumnName="id"),
			inverseJoinColumns=@JoinColumn(name="employee_id",
			referencedColumnName="emp_no")
		)
	private Set<Employee> team = new HashSet<Employee>(0);
	
//	@OneToMany(fetch=FetchType.LAZY)
//	@JoinColumn(name="fk_employee")
	@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
	@JoinColumn(name = "fk_project", updatable = false)
	private List<ProjectHours> hours = new ArrayList<ProjectHours>();
	
	
	public Project() {
	}

	public Project(String name, Department department, Manager manager, BigDecimal budget, LocalDate startDate, LocalDate endDate, String area) {
		this.name = name;
		this.department = department;
		this.manager = manager;
		this.budget = budget;
		this.startDate = startDate;
		this.endDate = endDate;
		this.area = area;
	}
	
	/**
	 * Relaciona el proyecto con el empleado e
	 * @param e
	 */
	public void addEmployee(Employee e) {
		this.team.add(e);	
	}
	
	/**
	 * A�ade un numero de horas al empleado e para un mes-a�o concreto
	 * @param e
	 * @param month
	 * @param year
	 * @param hours
	 */
	public void addHours(Employee e, int month, int year, int hours) {
		ProjectHours ph = new ProjectHours(month, year, hours, e, this);
		this.hours.add(ph);
	}

	public int getId() {
		return id;
	}
	
	public String getName() {
		return this.name;
	}

	public void setName(String name) {
		this.name = name;
	}
	

	public LocalDate getStartDate() {
		return startDate;
	}

	public void setStartDate(LocalDate startDate) {
		this.startDate = startDate;
	}

	public LocalDate getEndDate() {
		return endDate;
	}

	public void setEndDate(LocalDate endDate) {
		this.endDate = endDate;
	}

	public Department getDepartment() {
		return this.department;
	}

	public void setDepartment(Department Department) {
		this.department = Department;
	}

	public BigDecimal getBudget() {
		return this.budget;
	}

	public void setBudget(BigDecimal budget) {
		this.budget = budget;
	}

	public String getArea() {
		return this.area;
	}

	public void setArea(String area) {
		this.area = area;
	}

	public Manager getManager() {
		return manager;
	}

	public Set<Employee> getEmployees() {
		return this.team;
	}

	
	public List<ProjectHours> getHours(){
		return this.hours;
	}
	
	public void print () {
		System.out.println("Project " + this.name + " from department " + this.department.getDeptName() );
		System.out.print("Managed by ");
		this.manager.print();
		System.out.println("Project Team");
		System.out.println(this.team.toString());
		
	}

}
