/src/main/java/com/osf/jira/plugins/report/workplan/WorkPlan.java
Java | 726 lines | 574 code | 83 blank | 69 comment | 169 complexity | 8a925914b916e74023112ed2868acb83 MD5 | raw file
- /**
- * Copyright (c) 2008, Outsourcing Factory Inc.,
- * http://www.outsourcing-factory.com/
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * * Neither the name of the Outsourcing Factory Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- */
- package com.osf.jira.plugins.report.workplan;
-
- import java.text.DateFormat;
- import java.text.NumberFormat;
- import java.text.ParseException;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Calendar;
- import java.util.Collection;
- import java.util.Date;
- import java.util.HashMap;
- import java.util.HashSet;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- import java.util.TreeSet;
-
- import org.apache.log4j.Logger;
- import org.ofbiz.core.entity.DelegatorInterface;
- import org.ofbiz.core.entity.EntityCondition;
- import org.ofbiz.core.entity.EntityConditionList;
- import org.ofbiz.core.entity.EntityExpr;
- import org.ofbiz.core.entity.EntityOperator;
- import org.ofbiz.core.entity.GenericEntityException;
- import org.ofbiz.core.entity.GenericValue;
- import org.ofbiz.core.util.UtilMisc;
-
- import com.atlassian.core.util.DateUtils;
- import com.atlassian.core.util.DateUtils.Duration;
- import com.atlassian.core.util.InvalidDurationException;
- import com.atlassian.jira.component.ComponentAccessor;
- import com.atlassian.jira.config.properties.ApplicationProperties;
- import com.atlassian.jira.datetime.DateTimeFormatter;
- import com.atlassian.jira.datetime.DateTimeFormatterFactory;
- import com.atlassian.jira.datetime.DateTimeStyle;
- import com.atlassian.jira.issue.CustomFieldManager;
- import com.atlassian.jira.issue.Issue;
- import com.atlassian.jira.issue.IssueFactory;
- import com.atlassian.jira.issue.IssueFieldConstants;
- import com.atlassian.jira.issue.MutableIssue;
- import com.atlassian.jira.issue.fields.CustomField;
- import com.atlassian.jira.issue.search.SearchException;
- import com.atlassian.jira.plugin.report.impl.AbstractReport;
- import com.atlassian.jira.project.Project;
- import com.atlassian.jira.project.ProjectManager;
- import com.atlassian.jira.security.JiraAuthenticationContext;
- import com.atlassian.jira.security.PermissionManager;
- import com.atlassian.jira.security.roles.ProjectRole;
- import com.atlassian.jira.security.roles.ProjectRoleActors;
- import com.atlassian.jira.security.roles.ProjectRoleManager;
- import com.atlassian.jira.security.roles.RoleActor;
- import com.atlassian.jira.user.ApplicationUser;
- import com.atlassian.jira.user.util.UserManager;
- import com.atlassian.jira.user.util.UserUtil;
- import com.atlassian.jira.util.I18nHelper;
- import com.atlassian.jira.util.ParameterUtils;
- import com.atlassian.jira.web.action.ProjectActionSupport;
- import com.atlassian.jira.web.util.OutlookDateManager;
- import com.osf.jira.plugins.util.Holidays;
- import com.osf.jira.plugins.util.TextUtil;
-
- /**
- * @author Andriy Zhdanov
- */
- public class WorkPlan extends AbstractReport {
- private static final Logger log = Logger.getLogger(WorkPlan.class);
-
- private static final String ALLPROJECTS_KEY = "allProjects";
-
- private final IssueFactory issueFactory;
- private final OutlookDateManager outlookDateManager;
- private final UserManager userManager;
- private final UserUtil userUtil;
- private final PermissionManager permissionManager;
- private final JiraAuthenticationContext authenticationContext;
- private final ProjectRoleManager projectRoleManager;
- private final ProjectManager projectManager;
- private final CustomField issueStartDateCF;
- private final CustomField issueUtilizationCF;
- private final List splitStartDateCFs;
- private final List splitEstimateCFs;
- private final List splitUtilizationCFs;
- private final long secondsPerDay;
- private final long secondsPerWeek;
- private final DateTimeFormatterFactory dateTimeFormatterFactory;
-
- private Date reportStartDate;
-
- private Date reportEndDate;
-
- public WorkPlan(IssueFactory issueFactory,
- PermissionManager permissionManager,
- CustomFieldManager customFieldManager,
- OutlookDateManager outlookDateManager,
- JiraAuthenticationContext authenticationContext,
- UserManager userManager,
- ProjectRoleManager projectRoleManager,
- UserUtil userUtil,
- ProjectManager projectManager,
- DateTimeFormatterFactory dateTimeFormatterFactory) {
- this.issueFactory = issueFactory;
- this.permissionManager = permissionManager;
- this.outlookDateManager = outlookDateManager;
- this.authenticationContext = authenticationContext;
- this.userManager = userManager;
- this.projectRoleManager = projectRoleManager;
- this.userUtil = userUtil;
- this.projectManager = projectManager;
- this.dateTimeFormatterFactory = dateTimeFormatterFactory;
- issueStartDateCF = customFieldManager.getCustomFieldObjectByName("startDate");
- issueUtilizationCF = customFieldManager.getCustomFieldObjectByName("utilization");
-
- splitStartDateCFs = getSplitCustomFields(customFieldManager, "StartDate");
- splitEstimateCFs = getSplitCustomFields(customFieldManager, "Estimate");
- splitUtilizationCFs = getSplitCustomFields(customFieldManager, "Utilization");
-
- ApplicationProperties ap = ComponentAccessor.getApplicationProperties();
- secondsPerDay = new Float(Float.valueOf(ap.getDefaultBackedString("jira.timetracking.hours.per.day")) * 3600).longValue();
- secondsPerWeek = new Float(Float.valueOf(ap.getDefaultBackedString("jira.timetracking.days.per.week")) * secondsPerDay).longValue();
- }
-
- private List getSplitCustomFields(CustomFieldManager customFieldManager, String subName) {
- List customFields = new ArrayList();
- for (int i = 1;;i++) {
- CustomField cf = customFieldManager.getCustomFieldObjectByName("split" + i + subName);
- if (cf != null) {
- customFields.add(cf);
- } else {
- log.info("Found " + (i - 1) + " " + subName + " split custom fields");
- break;
- }
- }
- return customFields;
- }
-
- // searches for issues by remainingEstimate, startDate (if set) and assignee/project
- // note issues are filtered out by startDate later in getWorkPlan
- public List findIssues(String targetGroup, ApplicationUser targetUser, Long resourceProjectId, Long projectId, List<String> statusIds) throws GenericEntityException {
- EntityExpr estimatetExpr = new EntityExpr(IssueFieldConstants.TIME_ESTIMATE,
- EntityOperator.GREATER_THAN, new Long(0));
-
- EntityExpr entityExpr1;
- if (targetGroup != null && targetGroup.length() != 0) {
-
- log.info("Quering issues for group " + targetGroup);
- Set<ApplicationUser> users = userUtil.getAllUsersInGroupNames(
- Arrays.asList(new String[] {targetGroup}));
- if (users.size() > 0 ) {
- Set<String> userNames = new HashSet<String>();
- for (Iterator<ApplicationUser> i = users.iterator(); i.hasNext(); ) {
- String userName = i.next().getName();
- userNames.add(userName);
- }
- entityExpr1 = new EntityExpr("assignee",
- EntityOperator.IN, userNames);
- } else {
- // to avoid SQL Exception in SELECT ... WHERE (... (ASSIGNEE IN () ...)
- return new ArrayList();
- }
- } else if (targetUser != null) {
- entityExpr1 = new EntityExpr("assignee", EntityOperator.EQUALS, targetUser.getName());
- log.info("Quering issues for user " + targetUser.getName());
- } else if(resourceProjectId != null) {
- Project resourceProject = projectManager.getProjectObj(resourceProjectId);
- Collection<ProjectRole> projectRoles = projectRoleManager.getProjectRoles();
- Set<String> users = new HashSet<String>();
- for (ProjectRole projectRole : projectRoles) {
- Set<ApplicationUser> roleUsers = projectRoleManager.getProjectRoleActors(projectRole, resourceProject).getUsers();
- for (Iterator<ApplicationUser> j = roleUsers.iterator(); j.hasNext(); ) {
- ApplicationUser roleUser = j.next();
- users.add(roleUser.getName());
- }
- }
- if (users.size() > 0 ) {
- entityExpr1 = new EntityExpr("assignee", EntityOperator.IN, users);
- } else {
- // to avoid SQL Exception in SELECT ... WHERE (... (ASSIGNEE IN () ...)
- return new ArrayList();
- }
- } else {
- entityExpr1 = new EntityExpr("project",
- EntityOperator.EQUALS, projectId);
- log.info("Quering issues for projectId = " + projectId);
- }
-
- EntityCondition statusCondition;
- if (statusIds == null) {
- EntityExpr statusNotClosedExpr = new EntityExpr(IssueFieldConstants.STATUS, EntityOperator.NOT_EQUAL,
- Integer.toString(IssueFieldConstants.CLOSED_STATUS_ID));
- EntityExpr statusNotResolvedExpr = new EntityExpr(IssueFieldConstants.STATUS, EntityOperator.NOT_EQUAL,
- Integer.toString(IssueFieldConstants.RESOLVED_STATUS_ID));
- statusCondition = new EntityConditionList(
- UtilMisc.toList(statusNotClosedExpr, statusNotResolvedExpr), EntityOperator.AND);
-
- } else {
- List<EntityExpr> statusExprList = new ArrayList<EntityExpr>(statusIds.size());
- for (String statusId : statusIds) {
- EntityExpr statusExpr = new EntityExpr(IssueFieldConstants.STATUS, EntityOperator.EQUALS,
- statusId);
- statusExprList.add(statusExpr);
- }
- statusCondition = new EntityConditionList(statusExprList, EntityOperator.OR);
- }
-
- final EntityCondition entityCondition = new EntityConditionList(
- UtilMisc.toList(estimatetExpr, entityExpr1, statusCondition), EntityOperator.AND);
-
- /* not working!!! :(
- EntityExpr resolvedExpr = new EntityExpr(IssueFieldConstants.RESOLUTION, EntityOperator.,
- new Long(0));
- */
-
- return ComponentAccessor.getComponent(DelegatorInterface.class).findByCondition("Issue", entityCondition, null, null);
- }
-
- public Map getWorkPlan(I18nHelper i18nBean, Map params, ApplicationUser remoteUser) throws GenericEntityException, SearchException {
-
- String targetGroup = ParameterUtils.getStringParam(params, "targetGroup");
- ApplicationUser targetUser = ParameterUtils.getUserParam(params, "targetUser");
- Long targetResourceProjectId = ParameterUtils.getLongParam(params, "targetResourceProjectId");
- Long projectId = ParameterUtils.getLongParam(params, "projectId");
- List<String> statusIds = ParameterUtils.getListParam(params, "statusIds");
- if (statusIds == null) {
- String statusId = (String) params.get("statusIds");
- if (statusId != null && !statusId.isEmpty()) {
- statusIds = UtilMisc.toList(statusId);
- }
- }
-
- List issues = findIssues(targetGroup, targetUser, targetResourceProjectId, projectId, statusIds);
- Collection users = findUsers(targetGroup, targetUser, targetResourceProjectId, projectId);
-
- log.info("Query returned : " + issues.size() + " issues");
-
- Map workPlan = new HashMap();
-
- // fill in work planned per user
- for (Iterator issuesIterator = issues.iterator(); issuesIterator.hasNext();) {
- GenericValue genericIssue = (GenericValue) issuesIterator.next();
- MutableIssue issue = issueFactory.getIssue(genericIssue);
-
- EstimatedWork work = getEstimatedWorkFromGV(issue, i18nBean, params);
-
- // skip issue if work planned is out of range
- if (work.getSplits().size() == 0) {
- log.info("Skipping issue " + issue.getKey());
- continue;
- }
-
- ApplicationUser assignee = work.getAssignee();
-
- Map projectsPerAssignee = (Map) workPlan.get(assignee);
- if (projectsPerAssignee == null && users.contains(assignee)) {
- projectsPerAssignee = createEmptyProjectsPerAssignee();
- workPlan.put(assignee, projectsPerAssignee);
- }
-
- Project project = work.getProject();
- if (projectsPerAssignee != null) {
- ProjectBean projectBean = (ProjectBean) projectsPerAssignee.get(project.getKey());
- if(projectBean == null) {
- projectBean = new ProjectBean();
- projectBean.setKey(project.getKey());
- projectBean.setName(project.getName());
-
- projectsPerAssignee.put(project.getKey(), projectBean);
- }
- projectBean.getEstimatedWorks().add(work);
- }
- }
-
- return workPlan;
- }
-
- private Map createEmptyProjectsPerAssignee() {
- Map projectsPerAssignee = new HashMap();
-
- ProjectBean totalProject = new ProjectBean();
- totalProject.setKey(ALLPROJECTS_KEY);
- //totalProject.setName(i18nBean.getText("report.workplan.allprojects"));
- //FIXME: hardcoded l10n
- totalProject.setName("All Projects");
-
- projectsPerAssignee.put(ALLPROJECTS_KEY, totalProject);
- return projectsPerAssignee;
- }
-
- private Collection findUsers(String targetGroup, ApplicationUser targetUser, Long targetResourceProjectId, Long projectId) throws GenericEntityException {
- Set users = new HashSet();
-
- if (targetGroup != null && targetGroup.length() != 0) {
- users = userUtil.getAllUsersInGroupNames(
- Arrays.asList(new String[] {targetGroup}));
- } else if (targetUser != null) {
- users.add(targetUser);
- } else if(targetResourceProjectId != null || projectId != null) {
- Long membersSourceProjectId = (targetResourceProjectId != null ? targetResourceProjectId : projectId);
- Project resourceProject = projectManager.getProjectObj(membersSourceProjectId);
- Collection projectRoles = projectRoleManager.getProjectRoles();
- ProjectRoleActors allProjectRoleActors;
- Set actorsObjects;
- RoleActor actor;
- for (Iterator i = projectRoles.iterator(); i.hasNext(); ) {
- ProjectRole projectRole = (ProjectRole) i.next();
- if ("Users".equals(projectRole.getName())) {
- continue;
- }
-
- allProjectRoleActors = projectRoleManager.getProjectRoleActors(projectRole, resourceProject);
- if (allProjectRoleActors != null) {
- actorsObjects = allProjectRoleActors.getRoleActorsByType("atlassian-user-role-actor");
- if (actorsObjects != null && !actorsObjects.isEmpty()) {
- for (Iterator k = actorsObjects.iterator(); k.hasNext(); ) {
- actor = (RoleActor) k.next();
- for (Iterator j = actor.getUsers().iterator(); j.hasNext(); ) {
- ApplicationUser roleUser = (ApplicationUser)j.next();
- users.add(roleUser);
- }
- }
- }
- actorsObjects = allProjectRoleActors.getRoleActorsByType("atlassian-group-role-actor");
- if (actorsObjects != null && !actorsObjects.isEmpty()) {
- for (Iterator k = actorsObjects.iterator(); k.hasNext(); ) {
- actor = (RoleActor) k.next();
- for (Iterator j = actor.getUsers().iterator(); j.hasNext(); ) {
- ApplicationUser roleUser = (ApplicationUser) j.next();
- users.add(roleUser);
- }
- }
- }
- }
- }
- }
-
- return users;
- }
-
-
- private EstimatedWork getEstimatedWorkFromGV(Issue issue, I18nHelper i18nBean, Map params) {
- EstimatedWork work = new EstimatedWork(issue);
-
- work.setSplits(new TreeSet(new EstimatedWork.SplitComparator()));
-
- boolean doOldStyle = true;
-
- for (int i = 0; i < splitStartDateCFs.size(); i++) {
- CustomField splitStartDateCF = (CustomField) splitStartDateCFs.get(i);
-
- CustomField splitEstimateCF = null;
- if (splitEstimateCFs.size() > i) {
- splitEstimateCF = (CustomField) splitEstimateCFs.get(i);
- }
- long estimate = 0;
- if (splitEstimateCF != null) {
- String estimateStr = (String) splitEstimateCF.getValue(issue);
- if (estimateStr != null) {
-
- doOldStyle = false; // if at least one split value is specified
-
- try {
- estimate = DateUtils.getDurationSeconds(estimateStr, secondsPerDay, secondsPerWeek, Duration.MINUTE);
- } catch (InvalidDurationException e) {
- log.warn("Split is ignored: " + e.getMessage() + ": " + estimateStr);
- }
- }
- }
-
- CustomField splitUtilizationCF = null;
- if (splitUtilizationCFs.size() > i) {
- splitUtilizationCF = (CustomField) splitUtilizationCFs.get(i);
- }
-
- if (estimate > 0) {
- EstimatedWork.Split split =
- getSplit(issue, splitStartDateCF, estimate, splitUtilizationCF, i18nBean, params);
- if (split != null) {
- work.getSplits().add(split);
- }
- }
- }
- // use issue standard estimate field.
- if (doOldStyle) {
- long estimate = 0;
- if (issue.getEstimate() != null) {
- estimate = issue.getEstimate().longValue();
- }
-
- EstimatedWork.Split split =
- getSplit(issue, issueStartDateCF, estimate, issueUtilizationCF, i18nBean, params);
- if (split != null) {
- work.getSplits().add(split);
- }
- }
- return work;
- }
-
- // if utilizationStr is null, utilization will be 100%
- // return null if split does not fit into report date range
- private EstimatedWork.Split getSplit(Issue issue, CustomField startDateCF, long estimate, CustomField utilizationCF, I18nHelper i18nBean, Map params) {
- EstimatedWork.Split split = new EstimatedWork.Split();
- split.setEstimate(estimate);
-
- // startDate <- split1StartDate || startDate || today
- Date startDate = null;
- if (startDateCF != null) {
- startDate = (Date) startDateCF.getValue(issue);
- }
-
- // if no split start date set, use issue startDate custom field
- if (startDate == null && issueStartDateCF != null && issueStartDateCF != startDateCF) {
- startDate = (Date) issueStartDateCF.getValue(issue);
- }
-
- Calendar today = roundDate(Calendar.getInstance().getTime());
- // make remaining estimate start from today
- // if no start date specified
- if ((startDate == null ||
- // or planned start date passed, but beside splits,
- (startDate.before(today.getTime()) && issueStartDateCF == startDateCF)
- // only if today is in report range
- && reportEndDate.after(today.getTime()))) {
- startDate = today.getTime();
- }
-
- Calendar startCalendar = roundDate(startDate);
- split.setStartDate(startCalendar.getTime());
-
- String utilizationStr = null;
- if (utilizationCF != null) {
- utilizationStr = (String) utilizationCF.getValue(issue);
- }
-
- // if no split utilization set, use issue utilization custom field
- if (utilizationStr == null && issueUtilizationCF != null && issueUtilizationCF != utilizationCF) {
- utilizationStr = (String) issueUtilizationCF.getValue(issue);
- }
-
- NumberFormat percentFormat = NumberFormat.getPercentInstance(i18nBean.getLocale());
-
- double utilization = 0;
- if (utilizationStr != null) {
- try {
- utilization = percentFormat.parse(utilizationStr).doubleValue();
- } catch (ParseException e) {
- log.warn("Utilization will be 100%: " + e.getMessage());
- }
- }
- if (utilization <= 0) { // avoid illegal utilization
- utilization = 1; // 100%
- utilizationStr = percentFormat.format(utilization);
- }
-
- int estimateInDays = (int) Math.ceil(estimate / (secondsPerDay * utilization));
- estimateInDays += getNonWorkingDays(startDate, estimateInDays, params);
- split.setEstimateInDays(estimateInDays);
- split.setUtilizationStr(utilizationStr);
- split.setUtilization(utilization);
-
- if (startDate.after(reportEndDate)) {
- log.info("startDate " + startDate + " is after reportEndDate");
- return null; // does not fit into report date range
- } else if (startDate.after(reportStartDate)) {
- return split; // starts in report date range
- } else {
- Calendar endCalendar = (Calendar) startCalendar.clone();
- endCalendar.add(Calendar.DAY_OF_YEAR, estimateInDays);
- endCalendar.add(Calendar.MINUTE, -1);
- Date endDate = endCalendar.getTime();
-
- if (endDate.before(reportStartDate)) {
- log.info("endDate " + endDate + " is before reportStartDate");
- return null; // does not fit into report date range
- } else {
- split.setStartDate(reportStartDate);
- // adjust estimate in days
- while (startDate.before(reportStartDate)) {
- estimateInDays--;
- startCalendar.add(Calendar.DAY_OF_YEAR, 1);
- startDate = startCalendar.getTime();
- }
- split.setEstimateInDays(estimateInDays); // estimate is untouched
- return split; // is in report date range
- }
- }
- }
-
- // get number of non working dates in estimated work
- private int getNonWorkingDays(Date startDate, int estimateInDays, Map params) {
- int nonWorkingDays = 0;
- boolean workOnWeekends = params.containsKey("workOnWeekends");
- boolean workOnHolidays = params.containsKey("workOnHolidays");
- Calendar calendarDate = roundDate(startDate);
- while (estimateInDays-- > 0) {
- int dayOfWeek = calendarDate.get(Calendar.DAY_OF_WEEK);
- if ((!workOnWeekends && (dayOfWeek == Calendar.SATURDAY || dayOfWeek == Calendar.SUNDAY))
- || (!workOnHolidays && Holidays.getHolidays().containsKey(calendarDate.getTime()))) {
- nonWorkingDays++;
- estimateInDays++;
- }
- calendarDate.add(Calendar.DAY_OF_YEAR, 1);
- }
- return nonWorkingDays;
- }
-
- // fill dates (ordered list) and week days (corresponding to each date)
- public List getWeekDays(Date beginDate, Date endDate, I18nHelper i18nBean) {
- List weekDays = new ArrayList();
- DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, i18nBean.getLocale());
- Calendar calendarDate = getCalendar(endDate.getTime());
- calendarDate.add(Calendar.DAY_OF_YEAR, 1);
- endDate = calendarDate.getTime();
- calendarDate = roundDate(beginDate);
- while (endDate.after(calendarDate.getTime())) {
- int dayOfWeek = calendarDate.get(Calendar.DAY_OF_WEEK);
- WeekDay wd = new WeekDay();
- wd.setTime(calendarDate.getTime().getTime());
- wd.setKey(df.format(calendarDate.getTime()));
- String holiday = (String) Holidays.getHolidays().get(calendarDate.getTime());
- wd.setHoliday(holiday); // null if not a holiday
- wd.setCss((dayOfWeek == Calendar.SATURDAY
- || dayOfWeek == Calendar.SUNDAY
- || holiday != null) ? "nonBusinessDay" : "");
- weekDays.add(wd);
- calendarDate.add(Calendar.DAY_OF_YEAR, 1);
- }
- return weekDays;
- }
-
- public void calculateDayTotals(Map<ApplicationUser, Map<String, ProjectBean>> workPlan, List weekDays, Map params) {
- boolean workOnWeekends = params.containsKey("workOnWeekends");
- boolean workOnHolidays = params.containsKey("workOnHolidays");
- for (Iterator<ApplicationUser> i = workPlan.keySet().iterator(); i.hasNext();) {
- ApplicationUser assignee = i.next();
- Map<String, ProjectBean> projectsPerUser = workPlan.get(assignee);
- ProjectBean totalProject = projectsPerUser.get(ALLPROJECTS_KEY);
- Map dayTotalsPerUser = totalProject.getEstimateTotals();
- Map<Long, Long> dueDateTotalsPerUser = totalProject.getDueDateTotals();
- for (String projectKey : projectsPerUser.keySet()) {
- ProjectBean project = projectsPerUser.get(projectKey);
- List issuesPerProjectAndUser = project.getEstimatedWorks();
- Map dayTotalsPerUserAndProject = project.getEstimateTotals();
-
- for (Iterator j = issuesPerProjectAndUser.iterator(); j.hasNext();) {
- EstimatedWork ew = (EstimatedWork) j.next();
- for (Iterator k = ew.getSplits().iterator(); k.hasNext();) {
- EstimatedWork.Split split = (EstimatedWork.Split) k.next();
- long startTime = split.getStartTime();
- Calendar c = getCalendar(startTime);
- for (int day = 0; day < split.getEstimateInDays(); day++) {
- Long date = new Long(c.getTime().getTime());
- int dayOfWeek = c.get(Calendar.DAY_OF_WEEK);
- boolean isHoliday = Holidays.getHolidays().containsKey(c.getTime());
-
- c.add(Calendar.DAY_OF_YEAR, 1);
-
- if (!workOnWeekends && (dayOfWeek == Calendar.SATURDAY || dayOfWeek == Calendar.SUNDAY)
- || !workOnHolidays && isHoliday) {
- continue;
- }
-
- Long totalPerUser = (Long) dayTotalsPerUser.get(date);
- Long totalPerUserAndProject = (Long) dayTotalsPerUserAndProject.get(date);
- long miliseconds;
- // treat specially last day
- if (day < split.getEstimateInDays() - 1) {
- miliseconds = Math.round(split.getUtilization() * secondsPerDay);
- } else {
- // remaining hours
- miliseconds = Math.round(split.getEstimate() % (split.getUtilization() * secondsPerDay));
- if (miliseconds == 0) {
- // whole day
- miliseconds = Math.round(split.getUtilization() * secondsPerDay);
- }
- }
- if (totalPerUserAndProject == null) {
- dayTotalsPerUserAndProject.put(date, new Long(miliseconds));
- } else {
- dayTotalsPerUserAndProject.put(date, new Long(totalPerUserAndProject.longValue() + miliseconds));
- }
- if (totalPerUser == null) {
- dayTotalsPerUser.put(date, new Long(miliseconds));
- } else {
- dayTotalsPerUser.put(date, new Long(totalPerUser.longValue() + miliseconds));
- }
- }
- }
- Date dueDate = ew.getDueDate();
- if (false && dueDate != null) { // feature disabled
- Calendar due = roundDate(dueDate);
- Long date = due.getTimeInMillis();
- Long dueDateTotalPerUser = dueDateTotalsPerUser.get(date);
- Long miliseconds = ew.getEstimate();
- if (dueDateTotalPerUser == null) {
- dueDateTotalsPerUser.put(date, miliseconds);
- } else {
- dueDateTotalsPerUser.put(date, dueDateTotalPerUser + miliseconds);
- }
- }
- }
- }
- }
- }
-
- private Calendar roundDate(Date date) {
- Calendar calendarDate = Calendar.getInstance();
- calendarDate.setTime(date);
- calendarDate.set(Calendar.AM_PM, Calendar.AM);
- calendarDate.set(Calendar.HOUR, 0);
- calendarDate.set(Calendar.MINUTE, 0);
- calendarDate.set(Calendar.SECOND, 0);
- calendarDate.set(Calendar.MILLISECOND, 0);
- return calendarDate;
- }
-
- private Calendar getCalendar(long date) {
- Calendar calendarDate = Calendar.getInstance();
- calendarDate.setTimeInMillis(date);
- return calendarDate;
- }
-
- public String generateReport(ProjectActionSupport action, Map params, boolean htmlView) throws Exception {
- ApplicationUser remoteUser = authenticationContext.getLoggedInUser();
-
- I18nHelper i18nBean = authenticationContext.getI18nHelper();
-
- reportStartDate = roundDate(ParameterUtils.getDateParam(params, "startDate", i18nBean.getLocale())).getTime();
- reportEndDate = ParameterUtils.getDateParam(params, "endDate", i18nBean.getLocale());
- Calendar c = Calendar.getInstance();
- c.setTime(reportEndDate);
- c.set(Calendar.HOUR_OF_DAY, 23);
- c.set(Calendar.MINUTE, 59);
- c.set(Calendar.SECOND, 59);
- c.set(Calendar.MILLISECOND, 999);
- reportEndDate = c.getTime();
-
- Map velocityParams = new HashMap();
- Map workPlan = getWorkPlan(i18nBean, params, remoteUser);
- List weekDays = getWeekDays(reportStartDate, reportEndDate, i18nBean);
- calculateDayTotals(workPlan, weekDays, params);
- velocityParams.put("workPlan", workPlan);
- velocityParams.put("weekDays", weekDays);
- velocityParams.put("textUtil", new TextUtil(i18nBean));
- DateTimeFormatter formatter = dateTimeFormatterFactory.formatter().forLoggedInUser();
- velocityParams.put("outlookDate", formatter.withStyle(DateTimeStyle.DATE));
- velocityParams.put("additionalField", params.get("additionalField"));
- return descriptor.getHtml(htmlView ? "view" : "excel", velocityParams);
- }
-
- public String generateReportHtml(ProjectActionSupport action, Map params) throws Exception {
- return generateReport(action, params, true);
- }
-
- @Override
- public String generateReportExcel(ProjectActionSupport action, Map params) throws Exception {
- return generateReport(action, params, false);
- }
-
- /**
- * Validate the parameters set by the user.
- */
- @Override
- public void validate(ProjectActionSupport action, Map params)
- {
- ApplicationUser remoteUser = action.getLoggedInUser();
-
- Date startDate = ParameterUtils.getDateParam(params, "startDate", action.getLocale());
- Date endDate = ParameterUtils.getDateParam(params, "endDate", action.getLocale());
- Long projectId = ParameterUtils.getLongParam(params, "projectId");
- ApplicationUser targetUser = ParameterUtils.getUserParam(params, "targetUser");
-
- if (startDate == null) {
- action.addError("startDate", action.getText("report.workplan.startdate.required"));
- }
-
- if (endDate == null) {
- action.addError("endDate", action.getText("report.workplan.enddate.required"));
- }
- // The end date must be after the start date
- if (startDate != null && endDate != null && endDate.before(startDate)) {
- action.addError("endDate", action.getText("report.workplan.enddate.before.startdate"));
- }
- if (projectId == null && targetUser == null) {
- action.addError("projectId", action.getText("report.workplan.projectoruser.required"));
- }
- }
-
- /* TODO: get rid of it, but report looks ugly */
- @Override
- public boolean isExcelViewSupported() {
- return true;
- }
- }