/*
* Copyright (c) 2016 Haulmont
*
* 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.
*/
package com.haulmont.timesheets.service;
import com.haulmont.chile.core.model.MetaPropertyPath;
import com.haulmont.cuba.core.Persistence;
import com.haulmont.cuba.core.Transaction;
import com.haulmont.cuba.core.entity.Entity;
import com.haulmont.cuba.core.global.DataManager;
import com.haulmont.cuba.core.global.LoadContext;
import com.haulmont.cuba.core.global.Metadata;
import com.haulmont.cuba.security.entity.User;
import com.haulmont.timesheets.SystemDataManager;
import com.haulmont.timesheets.core.HolidaysCacheAPI;
import com.haulmont.timesheets.entity.*;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Nullable;
import javax.inject.Inject;
import java.util.*;
import static com.haulmont.timesheets.entity.ProjectRoleCode.APPROVER;
import static com.haulmont.timesheets.entity.ProjectRoleCode.MANAGER;
/**
* @author gorelov
*/
@Service(ProjectsService.NAME)
public class ProjectsServiceBean implements ProjectsService {
@Inject
protected DataManager dataManager;
@Inject
protected SystemDataManager systemDataManager;
@Inject
protected Persistence persistence;
@Inject
protected HolidaysCacheAPI holidaysCache;
@Inject
protected Metadata metadata;
protected List<Project> getAllProjects() {
LoadContext<Project> loadContext = new LoadContext<>(Project.class)
.setView("project-full");
loadContext.setQueryString("select e from ts$Project e");
return dataManager.loadList(loadContext);
}
@Override
@Transactional
public List<Project> getProjectChildren(Project parent) {
List<Project> projects = getAllProjects();
if (!projects.isEmpty()) {
List<Project> children = new ArrayList<>();
for (Project project : projects) {
if (parent.equals(project.getParent())) {
children.add(project);
children.addAll(getProjectChildren(project));
}
}
return children;
}
return Collections.emptyList();
}
@Nullable
@Override
public ProjectRole getUserProjectRole(Project project, User user) {
LoadContext<ProjectParticipant> loadContext = new LoadContext<>(ProjectParticipant.class)
.setView("projectParticipant-full");
loadContext.setQueryString("select e from ts$ProjectParticipant e " +
"where e.user.id = :userId and e.project.id = :projectId")
.setParameter("userId", user.getId())
.setParameter("projectId", project.getId());
ProjectParticipant participant = dataManager.load(loadContext);
return participant != null ? participant.getRole() : null;
}
@Nullable
@Override
public <T extends Entity> T getEntityByCode(Class<T> clazz, String code, String viewName) {
return systemDataManager.getEntityByCode(clazz, code, viewName);
}
@Override
public <T extends Entity> MetaPropertyPath getEntityMetaPropertyPath(Class<T> clazz, String property) {
return systemDataManager.getEntityMetaPropertyPath(clazz, property);
}
@Override
public List<TimeEntry> getTimeEntriesForPeriod(Date start, Date end, User user, @Nullable TimeEntryStatus status, @Nullable String viewName) {
LoadContext<TimeEntry> loadContext = new LoadContext<>(TimeEntry.class);
if (viewName != null) {
loadContext.setView(viewName);
}
String queryStr = "select e from ts$TimeEntry e where e.user.id = :userId and (e.date between :start and :end)";
if (status != null) {
queryStr += " and e.status = :status";
}
LoadContext.Query query = loadContext.setQueryString(queryStr)
.setParameter("start", start)
.setParameter("end", end)
.setParameter("userId", user.getId());
if (status != null) {
query.setParameter("status", status.getId());
}
return dataManager.loadList(loadContext);
}
@Override
public List<TimeEntry> getApprovableTimeEntriesForPeriod(
Date start, Date end, User approver, User user, @Nullable TimeEntryStatus status, @Nullable String viewName
) {
LoadContext<TimeEntry> loadContext = new LoadContext<>(TimeEntry.class);
if (viewName != null) {
loadContext.setView(viewName);
}
String queryStr = "select e from ts$TimeEntry e join e.task t join t.project pr join pr.participants p " +
"where p.user.id = :approverId and (p.role.code = '" + MANAGER.getId() + "' or p.role.code = '" + APPROVER.getId() + "') " +
"and e.user.id = :userId and (e.date between :start and :end)";
if (status != null) {
queryStr += " and e.status = :status";
}
LoadContext.Query query = loadContext.setQueryString(queryStr)
.setParameter("start", start)
.setParameter("end", end)
.setParameter("approverId", approver.getId())
.setParameter("userId", user.getId());
if (status != null) {
query.setParameter("status", status.getId());
}
return dataManager.loadList(loadContext);
}
@Override
public List<Holiday> getHolidaysForPeriod(Date start, Date end) {
return new ArrayList<>(holidaysCache.getHolidays(start, end));
}
@Override
public List<Task> getActiveTasksForUser(User user, @Nullable String viewName) {
LoadContext<Task> loadContext = new LoadContext<>(Task.class);
if (viewName != null) {
loadContext.setView(viewName);
}
loadContext.setQueryString("select e from ts$Task e join e.exclusiveParticipants p " +
"where p.user.id = :userId and e.status = 'active' order by e.project")
.setParameter("userId", user.getId());
List<Task> assignedTasks = dataManager.loadList(loadContext);
loadContext.setQueryString("select e from ts$Task e join e.project pr join pr.participants p " +
"where p.user.id = :userId and e.exclusiveParticipants is empty and e.status = 'active' order by e.project")
.setParameter("userId", user.getId());
List<Task> commonTasks = dataManager.loadList(loadContext);
if (assignedTasks.isEmpty() && commonTasks.isEmpty()) {
return Collections.emptyList();
}
List<Task> allTasks = new ArrayList<>(assignedTasks.size() + commonTasks.size());
allTasks.addAll(assignedTasks);
allTasks.addAll(commonTasks);
return allTasks;
}
@Override
public Map<String, Task> getActiveTasksForUserAndProject(User user, Project project, @Nullable String viewName) {
LoadContext<Task> loadContext = new LoadContext<>(Task.class);
if (viewName != null) {
loadContext.setView(viewName);
}
loadContext.setQueryString("select e from ts$Task e join e.exclusiveParticipants p " +
"where p.user.id = :userId and e.project.id = :projectId and e.status = 'active' order by e.project")
.setParameter("projectId", project.getId())
.setParameter("userId", user.getId());
List<Task> assignedTasks = dataManager.loadList(loadContext);
loadContext.setQueryString("select e from ts$Task e join e.project pr join pr.participants p " +
"where p.user.id = :userId and e.project.id = :projectId and e.exclusiveParticipants is empty " +
"and e.status = 'active' order by e.project")
.setParameter("projectId", project.getId())
.setParameter("userId", user.getId());
List<Task> commonTasks = dataManager.loadList(loadContext);
if (assignedTasks.isEmpty() && commonTasks.isEmpty()) {
return Collections.emptyMap();
}
List<Task> allTasks = new ArrayList<>(assignedTasks.size() + commonTasks.size());
allTasks.addAll(assignedTasks);
allTasks.addAll(commonTasks);
Map<String, Task> tasksMap = new TreeMap<>();
for (Task task : allTasks) {
tasksMap.put(task.getName(), task);
}
return tasksMap;
}
public List<Project> getActiveProjectsForUser(User user, @Nullable String viewName) {
LoadContext<Project> loadContext = new LoadContext<>(Project.class);
if (viewName != null) {
loadContext.setView(viewName);
}
LoadContext.Query query =
new LoadContext.Query("select pr from ts$Project pr, in(pr.participants) p " +
"where p.user.id = :userId and pr.status = 'open' order by pr.name")
.setParameter("userId", user.getId());
loadContext.setQuery(query);
return dataManager.loadList(loadContext);
}
public List<Project> getActiveManagedProjectsForUser(User user, @Nullable String viewName) {
LoadContext<Project> loadContext = new LoadContext<>(Project.class);
if (viewName != null) {
loadContext.setView(viewName);
}
LoadContext.Query query =
new LoadContext.Query("select pr from ts$Project pr, in(pr.participants) p " +
"where p.user.id = :userId " +
"and (p.role.code = '" + MANAGER.getId() + "' or p.role.code = '" + APPROVER.getId() + "') " +
"and pr.status = 'open'")
.setParameter("userId", user.getId());
loadContext.setQuery(query);
return dataManager.loadList(loadContext);
}
@Override
public boolean assignUsersToProjects(Collection<User> users, Collection<Project> projects, ProjectRole projectRole) {
List<ProjectParticipant> result = new ArrayList<>();
Transaction tx = persistence.createTransaction();
try {
List<UUID> ids = new ArrayList<>();
for (Project project : projects) {
ids.add(project.getId());
}
projects = persistence.getEntityManager().createQuery("select pr from ts$Project pr where pr.id in :ids", Project.class)
.setViewName("project-full")
.setParameter("ids", ids)
.getResultList();
for (Project project : projects) {
Set<User> assignedUsers = new HashSet<>();
for (ProjectParticipant projectParticipant : project.getParticipants()) {
assignedUsers.add(projectParticipant.getUser());
}
for (User user : users) {
if (!assignedUsers.contains(user)) {
ProjectParticipant projectParticipant = metadata.create(ProjectParticipant.class);
projectParticipant.setRole(projectRole);
projectParticipant.setUser(user);
projectParticipant.setProject(project);
result.add(projectParticipant);
}
}
}
for (ProjectParticipant projectParticipant : result) {
persistence.getEntityManager().persist(projectParticipant);
}
tx.commit();
} finally {
tx.end();
}
return CollectionUtils.isNotEmpty(result);
}
public List<Tag> getTagsForTheProject(@Nullable Project project, @Nullable String viewName) {
LoadContext<Tag> loadContext = new LoadContext<>(Tag.class);
if (viewName != null) {
loadContext.setView(viewName);
}
LoadContext.Query query =
new LoadContext.Query("select e from ts$Tag e left join e.tagType.projects pr where pr.id is null" +
" or (pr.id = :project)")
.setParameter("project", project);
loadContext.setQuery(query);
return dataManager.loadList(loadContext);
}
@Override
public List<Tag> getTagsWithTheTagType(TagType type, @Nullable String viewName) {
LoadContext<Tag> loadContext = new LoadContext<>(Tag.class);
if (viewName != null) {
loadContext.setView(viewName);
}
LoadContext.Query query =
new LoadContext.Query("select e from ts$Tag e where e.tagType.id = :type")
.setParameter("type", type);
loadContext.setQuery(query);
return dataManager.loadList(loadContext);
}
@Override
public List<ProjectParticipant> getProjectParticipants(Project project, @Nullable String viewName) {
LoadContext<ProjectParticipant> loadContext = new LoadContext<>(ProjectParticipant.class);
if (viewName != null) {
loadContext.setView(viewName);
}
loadContext.setQueryString("select e from ts$ProjectParticipant e where e.project.id = :projectId")
.setParameter("projectId", project.getId());
return dataManager.loadList(loadContext);
}
@Override
public List<User> getProjectUsers(Project project, @Nullable String viewName) {
LoadContext<User> loadContext = new LoadContext<>(User.class);
if (viewName != null) {
loadContext.setView(viewName);
}
loadContext.setQueryString("select u from sec$User u, ts$ProjectParticipant pp " +
"where pp.project.id = :projectId and pp.user.id = u.id")
.setParameter("projectId", project.getId());
return dataManager.loadList(loadContext);
}
@Override
public List<User> getManagedUsers(User manager, String viewName) {
LoadContext<User> loadContext = new LoadContext<>(User.class);
if (viewName != null) {
loadContext.setView(viewName);
}
loadContext.setQueryString("select distinct u from sec$User u, ts$ProjectParticipant pp " +
"join pp.project pr join pr.participants me " +
"where pp.user.id = u.id and me.user.id = :managerId " +
"and (me.role.code = '" + MANAGER.getId() + "' or me.role.code = '" + APPROVER.getId() + "')")
.setParameter("managerId", manager.getId());
return dataManager.loadList(loadContext);
}
@Override
public List<ActivityType> getActivityTypesForProject(Project project, @Nullable String viewName) {
LoadContext<ActivityType> loadContext = new LoadContext<>(ActivityType.class);
if (viewName != null) {
loadContext.setView(viewName);
}
loadContext.setQueryString("select e from ts$ActivityType e left join e.projects pr " +
"where pr.id is null or (pr.id = :projectId)")
.setParameter("projectId", project.getId());
return dataManager.loadList(loadContext);
}
}