/* * file: ResourceAssignment.java * author: Scott Melville * Jon Iles * copyright: (c) Packwood Software 2002-2003 * date: 15/08/2002 */ /* * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation; either version 2.1 of the License, or (at your * option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ package net.sf.mpxj; import java.util.Date; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.UUID; import net.sf.mpxj.common.AssignmentFieldLists; import net.sf.mpxj.common.BooleanHelper; import net.sf.mpxj.common.DateHelper; import net.sf.mpxj.common.DefaultTimephasedWorkContainer; import net.sf.mpxj.common.NumberHelper; import net.sf.mpxj.listener.FieldListener; /** * This class represents a resource assignment record from an MPX file. */ public final class ResourceAssignment extends ProjectEntity implements ProjectEntityWithUniqueID, FieldContainer { /** * Constructor. * * @param file The parent file to which this record belongs. */ public ResourceAssignment(ProjectFile file) { super(file); if (file.getProjectConfig().getAutoAssignmentUniqueID() == true) { setUniqueID(Integer.valueOf(file.getProjectConfig().getNextAssignmentUniqueID())); } } /** * Constructor. * * @param file The parent file to which this record belongs. * @param task The task to which this assignment is being made */ ResourceAssignment(ProjectFile file, Task task) { super(file); m_task = task; } /** * This method allows a resource assignment workgroup fields record * to be added to the current resource assignment. A maximum of * one of these records can be added to a resource assignment record. * * @return ResourceAssignmentWorkgroupFields object * @throws MPXJException if MSP defined limit of 1 is exceeded */ public ResourceAssignmentWorkgroupFields addWorkgroupAssignment() throws MPXJException { if (m_workgroup != null) { throw new MPXJException(MPXJException.MAXIMUM_RECORDS); } m_workgroup = new ResourceAssignmentWorkgroupFields(); return (m_workgroup); } /** * Retrieve the unique ID of this resource assignment. * * @return resource assignment unique ID */ @Override public Integer getUniqueID() { return (Integer) getCachedValue(AssignmentField.UNIQUE_ID); } /** * Set the unique ID of this resource assignment. * * @param uniqueID resource assignment unique ID */ @Override public void setUniqueID(Integer uniqueID) { set(AssignmentField.UNIQUE_ID, uniqueID); } /** * Returns the units of this resource assignment. * * @return units */ public Number getUnits() { return ((Number) getCachedValue(AssignmentField.ASSIGNMENT_UNITS)); } /** * Sets the units for this resource assignment. * * @param val units */ public void setUnits(Number val) { set(AssignmentField.ASSIGNMENT_UNITS, val); } /** * Returns the work of this resource assignment. * * @return work */ public Duration getWork() { return ((Duration) getCachedValue(AssignmentField.WORK)); } /** * Sets the work for this resource assignment. * * @param dur work */ public void setWork(Duration dur) { set(AssignmentField.WORK, dur); } /** * Retrieve the baseline start date. * * @return baseline start date */ public Date getBaselineStart() { return ((Date) getCachedValue(AssignmentField.BASELINE_START)); } /** * Set the baseline start date. * * @param start baseline start date */ public void setBaselineStart(Date start) { set(AssignmentField.BASELINE_START, start); } /** * Retrieve the actual start date. * * @return actual start date */ public Date getActualStart() { return ((Date) getCachedValue(AssignmentField.ACTUAL_START)); } /** * Set the actual start date. * * @param start actual start date */ public void setActualStart(Date start) { set(AssignmentField.ACTUAL_START, start); } /** * Retrieve the baseline finish date. * * @return baseline finish date */ public Date getBaselineFinish() { return ((Date) getCachedValue(AssignmentField.BASELINE_FINISH)); } /** * Set the baseline finish date. * * @param finish baseline finish */ public void setBaselineFinish(Date finish) { set(AssignmentField.BASELINE_FINISH, finish); } /** * Retrieve the actual finish date. * * @return actual finish date */ public Date getActualFinish() { return ((Date) getCachedValue(AssignmentField.ACTUAL_FINISH)); } /** * Set the actual finish date. * * @param finish actual finish */ public void setActualFinish(Date finish) { set(AssignmentField.ACTUAL_FINISH, finish); } /** * Returns the baseline work of this resource assignment. * * @return planned work */ public Duration getBaselineWork() { return ((Duration) getCachedValue(AssignmentField.BASELINE_WORK)); } /** * Sets the baseline work for this resource assignment. * * @param val planned work */ public void setBaselineWork(Duration val) { set(AssignmentField.BASELINE_WORK, val); } /** * Returns the actual completed work of this resource assignment. * * @return completed work */ public Duration getActualWork() { return ((Duration) getCachedValue(AssignmentField.ACTUAL_WORK)); } /** * Sets the actual completed work for this resource assignment. * * @param val actual completed work */ public void setActualWork(Duration val) { set(AssignmentField.ACTUAL_WORK, val); } /** * Returns the overtime work done of this resource assignment. * * @return overtime work */ public Duration getOvertimeWork() { return ((Duration) getCachedValue(AssignmentField.OVERTIME_WORK)); } /** * Sets the overtime work for this resource assignment. * * @param overtimeWork overtime work */ public void setOvertimeWork(Duration overtimeWork) { set(AssignmentField.OVERTIME_WORK, overtimeWork); } /** * Returns the cost of this resource assignment. * * @return cost */ public Number getCost() { return ((Number) getCachedValue(AssignmentField.COST)); } /** * Sets the cost for this resource assignment. * * @param cost cost */ public void setCost(Number cost) { set(AssignmentField.COST, cost); } /** * Returns the planned cost for this resource assignment. * * @return planned cost */ public Number getBaselineCost() { return ((Number) getCachedValue(AssignmentField.BASELINE_COST)); } /** * Sets the planned cost for this resource assignment. * * @param val planned cost */ public void setBaselineCost(Number val) { set(AssignmentField.BASELINE_COST, val); } /** * Returns the actual cost for this resource assignment. * * @return actual cost */ public Number getActualCost() { return ((Number) getCachedValue(AssignmentField.ACTUAL_COST)); } /** * Sets the actual cost so far incurred for this resource assignment. * * @param actualCost actual cost */ public void setActualCost(Number actualCost) { set(AssignmentField.ACTUAL_COST, actualCost); } /** * Returns the start of this resource assignment. * * @return start date */ public Date getStart() { Date result = (Date) getCachedValue(AssignmentField.START); if (result == null) { result = getTask().getStart(); } return result; } /** * Sets the start date for this resource assignment. * * @param val start date */ public void setStart(Date val) { set(AssignmentField.START, val); } /** * Returns the finish date for this resource assignment. * * @return finish date */ public Date getFinish() { Date result = (Date) getCachedValue(AssignmentField.FINISH); if (result == null) { result = getTask().getFinish(); } return result; } /** * Sets the finish date for this resource assignment. * * @param val finish date */ public void setFinish(Date val) { set(AssignmentField.FINISH, val); } /** * Returns the delay for this resource assignment. * * @return delay */ public Duration getDelay() { return ((Duration) getCachedValue(AssignmentField.ASSIGNMENT_DELAY)); } /** * Sets the delay for this resource assignment. * * @param dur delay */ public void setDelay(Duration dur) { set(AssignmentField.ASSIGNMENT_DELAY, dur); } /** * Returns the resources unique id for this resource assignment. * * @return resources unique id */ public Integer getResourceUniqueID() { return (Integer) getCachedValue(AssignmentField.RESOURCE_UNIQUE_ID); } /** * Sets the resources unique id for this resource assignment. * * @param val resources unique id */ public void setResourceUniqueID(Integer val) { set(AssignmentField.RESOURCE_UNIQUE_ID, val); } /** * Gets the Resource Assignment Workgroup Fields if one exists. * * @return workgroup assignment object */ public ResourceAssignmentWorkgroupFields getWorkgroupAssignment() { return (m_workgroup); } /** * This method retrieves a reference to the task with which this * assignment is associated. * * @return task */ public Task getTask() { if (m_task == null) { m_task = getParentFile().getTaskByUniqueID(getTaskUniqueID()); } return (m_task); } /** * This method retrieves a reference to the resource with which this * assignment is associated. * * @return resource */ public Resource getResource() { return (getParentFile().getResourceByUniqueID(getResourceUniqueID())); } /** * This method returns the Work Contour type of this Assignment. * * @return the Work Contour type */ public WorkContour getWorkContour() { return ((WorkContour) getCachedValue(AssignmentField.WORK_CONTOUR)); } /** * This method sets the Work Contour type of this Assignment. * * @param workContour the Work Contour type */ public void setWorkContour(WorkContour workContour) { set(AssignmentField.WORK_CONTOUR, workContour); } /** * Removes this resource assignment from the project. */ public void remove() { getParentFile().getAllResourceAssignments().remove(this); } /** * Returns the remaining work for this resource assignment. * * @return remaining work */ public Duration getRemainingWork() { return ((Duration) getCachedValue(AssignmentField.REMAINING_WORK)); } /** * Sets the remaining work for this resource assignment. * * @param remainingWork remaining work */ public void setRemainingWork(Duration remainingWork) { set(AssignmentField.REMAINING_WORK, remainingWork); } /** * Retrieves the leveling delay for this resource assignment. * * @return leveling delay */ public Duration getLevelingDelay() { return ((Duration) getCachedValue(AssignmentField.LEVELING_DELAY)); } /** * Sets the leveling delay for this resource assignment. * * @param levelingDelay leveling delay */ public void setLevelingDelay(Duration levelingDelay) { set(AssignmentField.LEVELING_DELAY, levelingDelay); } /** * Retrieves the timephased breakdown of the completed work for this * resource assignment. * * @return timephased completed work */ public List<TimephasedWork> getTimephasedActualWork() { return m_timephasedActualWork == null ? null : m_timephasedActualWork.getData(); } /** * Sets the timephased breakdown of the completed work for this * resource assignment. * * @param data timephased data */ public void setTimephasedActualWork(TimephasedWorkContainer data) { m_timephasedActualWork = data; } /** * Retrieves the timephased breakdown of the planned work for this * resource assignment. * * @return timephased planned work */ public List<TimephasedWork> getTimephasedWork() { return m_timephasedWork == null ? null : m_timephasedWork.getData(); } /** * Sets the timephased breakdown of the planned work for this * resource assignment. * * @param data timephased data */ public void setTimephasedWork(DefaultTimephasedWorkContainer data) { m_timephasedWork = data; } /** * Retrieves the timephased breakdown of the planned overtime work for this * resource assignment. * * @return timephased planned work */ public List<TimephasedWork> getTimephasedOvertimeWork() { if (m_timephasedOvertimeWork == null && m_timephasedWork != null && getOvertimeWork() != null) { double perDayFactor = getRemainingOvertimeWork().getDuration() / (getRemainingWork().getDuration() - getRemainingOvertimeWork().getDuration()); double totalFactor = getRemainingOvertimeWork().getDuration() / getRemainingWork().getDuration(); perDayFactor = Double.isNaN(perDayFactor) ? 0 : perDayFactor; totalFactor = Double.isNaN(totalFactor) ? 0 : totalFactor; m_timephasedOvertimeWork = new DefaultTimephasedWorkContainer(m_timephasedWork, perDayFactor, totalFactor); } return m_timephasedOvertimeWork == null ? null : m_timephasedOvertimeWork.getData(); } /** * Sets the timephased breakdown of the actual overtime work * for this assignment. * * @param data timephased work */ public void setTimephasedActualOvertimeWork(TimephasedWorkContainer data) { m_timephasedActualOvertimeWork = data; } /** * Retrieves the timephased breakdown of the actual overtime work for this * resource assignment. * * @return timephased planned work */ public List<TimephasedWork> getTimephasedActualOvertimeWork() { return m_timephasedActualOvertimeWork == null ? null : m_timephasedActualOvertimeWork.getData(); } /** * Retrieves the timephased breakdown of cost. * * @return timephased cost */ public List<TimephasedCost> getTimephasedCost() { if (m_timephasedCost == null) { Resource r = getResource(); ResourceType type = r != null ? r.getType() : ResourceType.WORK; //for Work and Material resources, we will calculate in the normal way if (type != ResourceType.COST) { if (m_timephasedWork != null && m_timephasedWork.hasData()) { if (hasMultipleCostRates()) { m_timephasedCost = getTimephasedCostMultipleRates(getTimephasedWork(), getTimephasedOvertimeWork()); } else { m_timephasedCost = getTimephasedCostSingleRate(getTimephasedWork(), getTimephasedOvertimeWork()); } } } else { m_timephasedCost = getTimephasedCostFixedAmount(); } } return m_timephasedCost; } /** * Retrieves the timephased breakdown of actual cost. * * @return timephased actual cost */ public List<TimephasedCost> getTimephasedActualCost() { if (m_timephasedActualCost == null) { Resource r = getResource(); ResourceType type = r != null ? r.getType() : ResourceType.WORK; //for Work and Material resources, we will calculate in the normal way if (type != ResourceType.COST) { if (m_timephasedActualWork != null && m_timephasedActualWork.hasData()) { if (hasMultipleCostRates()) { m_timephasedActualCost = getTimephasedCostMultipleRates(getTimephasedActualWork(), getTimephasedActualOvertimeWork()); } else { m_timephasedActualCost = getTimephasedCostSingleRate(getTimephasedActualWork(), getTimephasedActualOvertimeWork()); } } } else { m_timephasedActualCost = getTimephasedActualCostFixedAmount(); } } return m_timephasedActualCost; } /** * Generates timephased costs from timephased work where a single cost rate * applies to the whole assignment. * * @param standardWorkList timephased work * @param overtimeWorkList timephased work * @return timephased cost */ private List<TimephasedCost> getTimephasedCostSingleRate(List<TimephasedWork> standardWorkList, List<TimephasedWork> overtimeWorkList) { List<TimephasedCost> result = new LinkedList<TimephasedCost>(); //just return an empty list if there is no timephased work passed in if (standardWorkList == null) { return result; } //takes care of the situation where there is no timephased overtime work Iterator<TimephasedWork> overtimeIterator = overtimeWorkList == null ? java.util.Collections.<TimephasedWork> emptyList().iterator() : overtimeWorkList.iterator(); for (TimephasedWork standardWork : standardWorkList) { CostRateTableEntry rate = getCostRateTableEntry(standardWork.getStart()); double standardRateValue = rate.getStandardRate().getAmount(); TimeUnit standardRateUnits = rate.getStandardRate().getUnits(); double overtimeRateValue = 0; TimeUnit overtimeRateUnits = standardRateUnits; if (rate.getOvertimeRate() != null) { overtimeRateValue = rate.getOvertimeRate().getAmount(); overtimeRateUnits = rate.getOvertimeRate().getUnits(); } TimephasedWork overtimeWork = overtimeIterator.hasNext() ? overtimeIterator.next() : null; Duration standardWorkPerDay = standardWork.getAmountPerDay(); if (standardWorkPerDay.getUnits() != standardRateUnits) { standardWorkPerDay = standardWorkPerDay.convertUnits(standardRateUnits, getParentFile().getProjectProperties()); } Duration totalStandardWork = standardWork.getTotalAmount(); if (totalStandardWork.getUnits() != standardRateUnits) { totalStandardWork = totalStandardWork.convertUnits(standardRateUnits, getParentFile().getProjectProperties()); } Duration overtimeWorkPerDay; Duration totalOvertimeWork; if (overtimeWork == null || overtimeWork.getTotalAmount().getDuration() == 0) { overtimeWorkPerDay = Duration.getInstance(0, standardWorkPerDay.getUnits()); totalOvertimeWork = Duration.getInstance(0, standardWorkPerDay.getUnits()); } else { overtimeWorkPerDay = overtimeWork.getAmountPerDay(); if (overtimeWorkPerDay.getUnits() != overtimeRateUnits) { overtimeWorkPerDay = overtimeWorkPerDay.convertUnits(overtimeRateUnits, getParentFile().getProjectProperties()); } totalOvertimeWork = overtimeWork.getTotalAmount(); if (totalOvertimeWork.getUnits() != overtimeRateUnits) { totalOvertimeWork = totalOvertimeWork.convertUnits(overtimeRateUnits, getParentFile().getProjectProperties()); } } double costPerDay = (standardWorkPerDay.getDuration() * standardRateValue) + (overtimeWorkPerDay.getDuration() * overtimeRateValue); double totalCost = (totalStandardWork.getDuration() * standardRateValue) + (totalOvertimeWork.getDuration() * overtimeRateValue); //if the overtime work does not span the same number of days as the work, //then we have to split this into two TimephasedCost values if (overtimeWork == null || (overtimeWork.getFinish().equals(standardWork.getFinish()))) { //normal way TimephasedCost cost = new TimephasedCost(); cost.setStart(standardWork.getStart()); cost.setFinish(standardWork.getFinish()); cost.setModified(standardWork.getModified()); cost.setAmountPerDay(Double.valueOf(costPerDay)); cost.setTotalAmount(Double.valueOf(totalCost)); result.add(cost); } else { //prorated way result.addAll(splitCostProrated(getCalendar(), totalCost, costPerDay, standardWork.getStart())); } } return result; } /** * Generates timephased costs from timephased work where multiple cost rates * apply to the assignment. * * @param standardWorkList timephased work * @param overtimeWorkList timephased work * @return timephased cost */ private List<TimephasedCost> getTimephasedCostMultipleRates(List<TimephasedWork> standardWorkList, List<TimephasedWork> overtimeWorkList) { List<TimephasedWork> standardWorkResult = new LinkedList<TimephasedWork>(); List<TimephasedWork> overtimeWorkResult = new LinkedList<TimephasedWork>(); CostRateTable table = getCostRateTable(); ProjectCalendar calendar = getCalendar(); Iterator<TimephasedWork> iter = overtimeWorkList.iterator(); for (TimephasedWork standardWork : standardWorkList) { TimephasedWork overtimeWork = iter.hasNext() ? iter.next() : null; int startIndex = getCostRateTableEntryIndex(standardWork.getStart()); int finishIndex = getCostRateTableEntryIndex(standardWork.getFinish()); if (startIndex == finishIndex) { standardWorkResult.add(standardWork); if (overtimeWork != null) { overtimeWorkResult.add(overtimeWork); } } else { standardWorkResult.addAll(splitWork(table, calendar, standardWork, startIndex)); if (overtimeWork != null) { overtimeWorkResult.addAll(splitWork(table, calendar, overtimeWork, startIndex)); } } } return getTimephasedCostSingleRate(standardWorkResult, overtimeWorkResult); } /** * Generates timephased costs from the assignment's cost value. Used for Cost type Resources. * * @return timephased cost */ private List<TimephasedCost> getTimephasedCostFixedAmount() { List<TimephasedCost> result = new LinkedList<TimephasedCost>(); ProjectCalendar cal = getCalendar(); double remainingCost = getRemainingCost().doubleValue(); if (remainingCost > 0) { AccrueType accrueAt = getResource().getAccrueAt(); if (accrueAt == AccrueType.START) { result.add(splitCostStart(cal, remainingCost, getStart())); } else if (accrueAt == AccrueType.END) { result.add(splitCostEnd(cal, remainingCost, getFinish())); } else { //for prorated, we have to deal with it differently depending on whether or not //any actual has been entered, since we want to mimic the other timephased data //where planned and actual values do not overlap double numWorkingDays = cal.getWork(getStart(), getFinish(), TimeUnit.DAYS).getDuration(); double standardAmountPerDay = getCost().doubleValue() / numWorkingDays; if (getActualCost().intValue() > 0) { //need to get three possible blocks of data: one for the possible partial amount //overlap with timephased actual cost; one with all the standard amount days //that happen after the actual cost stops; and one with any remaining //partial day cost amount int numActualDaysUsed = (int) Math.ceil(getActualCost().doubleValue() / standardAmountPerDay); Date actualWorkFinish = cal.getDate(getStart(), Duration.getInstance(numActualDaysUsed, TimeUnit.DAYS), false); double partialDayActualAmount = getActualCost().doubleValue() % standardAmountPerDay; if (partialDayActualAmount > 0) { double dayAmount = standardAmountPerDay < remainingCost ? standardAmountPerDay - partialDayActualAmount : remainingCost; result.add(splitCostEnd(cal, dayAmount, actualWorkFinish)); remainingCost -= dayAmount; } //see if there's anything left to work with if (remainingCost > 0) { //have to split up the amount into standard prorated amount days and whatever is left result.addAll(splitCostProrated(cal, remainingCost, standardAmountPerDay, cal.getNextWorkStart(actualWorkFinish))); } } else { //no actual cost to worry about, so just a standard split from the beginning of the assignment result.addAll(splitCostProrated(cal, remainingCost, standardAmountPerDay, getStart())); } } } return result; } /** * Generates timephased actual costs from the assignment's cost value. Used for Cost type Resources. * * @return timephased cost */ private List<TimephasedCost> getTimephasedActualCostFixedAmount() { List<TimephasedCost> result = new LinkedList<TimephasedCost>(); double actualCost = getActualCost().doubleValue(); if (actualCost > 0) { AccrueType accrueAt = getResource().getAccrueAt(); if (accrueAt == AccrueType.START) { result.add(splitCostStart(getCalendar(), actualCost, getActualStart())); } else if (accrueAt == AccrueType.END) { result.add(splitCostEnd(getCalendar(), actualCost, getActualFinish())); } else { //for prorated, we have to deal with it differently; have to 'fill up' each //day with the standard amount before going to the next one double numWorkingDays = getCalendar().getWork(getStart(), getFinish(), TimeUnit.DAYS).getDuration(); double standardAmountPerDay = getCost().doubleValue() / numWorkingDays; result.addAll(splitCostProrated(getCalendar(), actualCost, standardAmountPerDay, getActualStart())); } } return result; } /** * Used for Cost type Resources. * * Generates a TimphasedCost block for the total amount on the start date. This is useful * for Cost resources that have an AccrueAt value of Start. * * @param calendar calendar used by this assignment * @param totalAmount cost amount for this block * @param start start date of the timephased cost block * @return timephased cost */ private TimephasedCost splitCostStart(ProjectCalendar calendar, double totalAmount, Date start) { TimephasedCost cost = new TimephasedCost(); cost.setStart(start); cost.setFinish(calendar.getDate(start, Duration.getInstance(1, TimeUnit.DAYS), false)); cost.setAmountPerDay(Double.valueOf(totalAmount)); cost.setTotalAmount(Double.valueOf(totalAmount)); return cost; } /** * Used for Cost type Resources. * * Generates a TimphasedCost block for the total amount on the finish date. This is useful * for Cost resources that have an AccrueAt value of End. * * @param calendar calendar used by this assignment * @param totalAmount cost amount for this block * @param finish finish date of the timephased cost block * @return timephased cost */ private TimephasedCost splitCostEnd(ProjectCalendar calendar, double totalAmount, Date finish) { TimephasedCost cost = new TimephasedCost(); cost.setStart(calendar.getStartDate(finish, Duration.getInstance(1, TimeUnit.DAYS))); cost.setFinish(finish); cost.setAmountPerDay(Double.valueOf(totalAmount)); cost.setTotalAmount(Double.valueOf(totalAmount)); return cost; } /** * Used for Cost type Resources. * * Generates up to two TimephasedCost blocks for a cost amount. The first block will contain * all the days using the standardAmountPerDay, and a second block will contain any * final amount that is not enough for a complete day. This is useful for Cost resources * who have an AccrueAt value of Prorated. * * @param calendar calendar used by this assignment * @param totalAmount cost amount to be prorated * @param standardAmountPerDay cost amount for a normal working day * @param start date of the first timephased cost block * @return timephased cost */ private List<TimephasedCost> splitCostProrated(ProjectCalendar calendar, double totalAmount, double standardAmountPerDay, Date start) { List<TimephasedCost> result = new LinkedList<TimephasedCost>(); double numStandardAmountDays = Math.floor(totalAmount / standardAmountPerDay); double amountForLastDay = totalAmount % standardAmountPerDay; //first block contains all the normal work at the beginning of the assignments life, if any if (numStandardAmountDays > 0) { Date finishStandardBlock = calendar.getDate(start, Duration.getInstance(numStandardAmountDays, TimeUnit.DAYS), false); TimephasedCost standardBlock = new TimephasedCost(); standardBlock.setAmountPerDay(Double.valueOf(standardAmountPerDay)); standardBlock.setStart(start); standardBlock.setFinish(finishStandardBlock); standardBlock.setTotalAmount(Double.valueOf(numStandardAmountDays * standardAmountPerDay)); result.add(standardBlock); start = calendar.getNextWorkStart(finishStandardBlock); } //next block contains the partial day amount, if any if (amountForLastDay > 0) { TimephasedCost nextBlock = new TimephasedCost(); nextBlock.setAmountPerDay(Double.valueOf(amountForLastDay)); nextBlock.setTotalAmount(Double.valueOf(amountForLastDay)); nextBlock.setStart(start); nextBlock.setFinish(calendar.getDate(start, Duration.getInstance(1, TimeUnit.DAYS), false)); result.add(nextBlock); } return result; } /** * Splits timephased work segments in line with cost rates. Note that this is * an approximation - where a rate changes during a working day, the second * rate is used for the whole day. * * @param table cost rate table * @param calendar calendar used by this assignment * @param work timephased work segment * @param rateIndex rate applicable at the start of the timephased work segment * @return list of segments which replace the one supplied by the caller */ private List<TimephasedWork> splitWork(CostRateTable table, ProjectCalendar calendar, TimephasedWork work, int rateIndex) { List<TimephasedWork> result = new LinkedList<TimephasedWork>(); work.setTotalAmount(Duration.getInstance(0, work.getAmountPerDay().getUnits())); while (true) { CostRateTableEntry rate = table.get(rateIndex); Date splitDate = rate.getEndDate(); if (splitDate.getTime() >= work.getFinish().getTime()) { result.add(work); break; } Date currentPeriodEnd = calendar.getPreviousWorkFinish(splitDate); TimephasedWork currentPeriod = new TimephasedWork(work); currentPeriod.setFinish(currentPeriodEnd); result.add(currentPeriod); Date nextPeriodStart = calendar.getNextWorkStart(splitDate); work.setStart(nextPeriodStart); ++rateIndex; } return result; } /** * Used to determine if multiple cost rates apply to this assignment. * * @return true if multiple cost rates apply to this assignment */ private boolean hasMultipleCostRates() { boolean result = false; CostRateTable table = getCostRateTable(); if (table != null) { // // We assume here that if there is just one entry in the cost rate // table, this is an open ended rate which covers any work, it won't // have specific dates attached to it. // if (table.size() > 1) { // // If we have multiple rates in the table, see if the same rate // is in force at the start and the end of the aaaignment. // CostRateTableEntry startEntry = table.getEntryByDate(getStart()); CostRateTableEntry finishEntry = table.getEntryByDate(getFinish()); result = (startEntry != finishEntry); } } return result; } /** * Retrieves the cost rate table entry active on a given date. * * @param date target date * @return cost rate table entry */ private CostRateTableEntry getCostRateTableEntry(Date date) { CostRateTableEntry result; CostRateTable table = getCostRateTable(); if (table == null) { Resource resource = getResource(); result = new CostRateTableEntry(resource.getStandardRate(), TimeUnit.HOURS, resource.getOvertimeRate(), TimeUnit.HOURS, resource.getCostPerUse(), null); } else { if (table.size() == 1) { result = table.get(0); } else { result = table.getEntryByDate(date); } } return result; } /** * Retrieves the index of a cost rate table entry active on a given date. * * @param date target date * @return cost rate table entry index */ private int getCostRateTableEntryIndex(Date date) { int result = -1; CostRateTable table = getCostRateTable(); if (table != null) { if (table.size() == 1) { result = 0; } else { result = table.getIndexByDate(date); } } return result; } /** * Retrieve a flag indicating if this resource assignment has timephased * data associated with it. * * @return true if this resource assignment has timephased data */ public boolean getHasTimephasedData() { return (m_timephasedWork != null && m_timephasedWork.hasData()) || (m_timephasedActualWork != null && m_timephasedActualWork.hasData()); } /** * Set timephased baseline work. Note that index 0 represents "Baseline", * index 1 represents "Baseline1" and so on. * * @param index baseline index * @param data timephased data */ public void setTimephasedBaselineWork(int index, TimephasedWorkContainer data) { m_timephasedBaselineWork[index] = data; } /** * Set timephased baseline cost. Note that index 0 represents "Baseline", * index 1 represents "Baseline1" and so on. * * @param index baseline index * @param data timephased data */ public void setTimephasedBaselineCost(int index, TimephasedCostContainer data) { m_timephasedBaselineCost[index] = data; } /** * Retrieve timephased baseline work. Note that index 0 represents "Baseline", * index 1 represents "Baseline1" and so on. * * @param index baseline index * @return timephased work, or null if no baseline is present */ public List<TimephasedWork> getTimephasedBaselineWork(int index) { return m_timephasedBaselineWork[index] == null ? null : m_timephasedBaselineWork[index].getData(); } /** * Retrieve timephased baseline cost. Note that index 0 represents "Baseline", * index 1 represents "Baseline1" and so on. * * @param index baseline index * @return timephased work, or null if no baseline is present */ public List<TimephasedCost> getTimephasedBaselineCost(int index) { return m_timephasedBaselineCost[index] == null ? null : m_timephasedBaselineCost[index].getData(); } /** * Retrieves the calendar used for this resource assignment. * * @return ProjectCalendar instance */ public ProjectCalendar getCalendar() { ProjectCalendar calendar = null; Resource resource = getResource(); if (resource != null) { calendar = resource.getResourceCalendar(); } Task task = getTask(); if (calendar == null || task.getIgnoreResourceCalendar()) { calendar = task.getCalendar(); } if (calendar == null) { calendar = getParentFile().getDefaultCalendar(); } return calendar; } /** * Retrieve the variable rate time units, null if fixed rate. * * @return variable rate time units */ public TimeUnit getVariableRateUnits() { return (TimeUnit) getCachedValue(AssignmentField.VARIABLE_RATE_UNITS); } /** * Set the variable rate time units, null if fixed rate. * * @param variableRateUnits variable rate units */ public void setVariableRateUnits(TimeUnit variableRateUnits) { set(AssignmentField.VARIABLE_RATE_UNITS, variableRateUnits); } /** * Set the parent task unique ID. * * @param id task unique ID */ public void setTaskUniqueID(Integer id) { set(AssignmentField.TASK_UNIQUE_ID, id); } /** * Retrieve the parent task unique ID. * * @return task unique ID */ public Integer getTaskUniqueID() { return (Integer) getCachedValue(AssignmentField.TASK_UNIQUE_ID); } /** * Retrieves the budget cost. * * @return budget cost */ public Number getBudgetCost() { return (Number) getCachedValue(AssignmentField.BUDGET_COST); } /** * Sets the budget cost. * * @param cost budget cost */ public void setBudgetCost(Number cost) { set(AssignmentField.BUDGET_COST, cost); } /** * Retrieves the budget work value. * * @return budget work */ public Duration getBudgetWork() { return (Duration) getCachedValue(AssignmentField.BUDGET_WORK); } /** * Sets the budget work value. * * @param work budget work */ public void setBudgetWork(Duration work) { set(AssignmentField.BUDGET_WORK, work); } /** * Retrieves the baseline budget cost. * * @return baseline budget cost */ public Number getBaselineBudgetCost() { return (Number) getCachedValue(AssignmentField.BASELINE_BUDGET_COST); } /** * Sets the baseline budget cost. * * @param cost baseline budget cost */ public void setBaselineBudgetCost(Number cost) { set(AssignmentField.BASELINE_BUDGET_COST, cost); } /** * Retrieves the baseline budget work value. * * @return baseline budget work */ public Duration getBaselineBudgetWork() { return (Duration) getCachedValue(AssignmentField.BASELINE_BUDGET_WORK); } /** * Sets the baseline budget work value. * * @param work baseline budget work */ public void setBaselineBudgetWork(Duration work) { set(AssignmentField.BASELINE_BUDGET_WORK, work); } /** * Set a baseline value. * * @param baselineNumber baseline index (1-10) * @param value baseline value */ public void setBaselineCost(int baselineNumber, Number value) { set(selectField(AssignmentFieldLists.BASELINE_COSTS, baselineNumber), value); } /** * Set a baseline value. * * @param baselineNumber baseline index (1-10) * @param value baseline value */ public void setBaselineWork(int baselineNumber, Duration value) { set(selectField(AssignmentFieldLists.BASELINE_WORKS, baselineNumber), value); } /** * Retrieve a baseline value. * * @param baselineNumber baseline index (1-10) * @return baseline value */ public Duration getBaselineWork(int baselineNumber) { return ((Duration) getCachedValue(selectField(AssignmentFieldLists.BASELINE_WORKS, baselineNumber))); } /** * Retrieve a baseline value. * * @param baselineNumber baseline index (1-10) * @return baseline value */ public Number getBaselineCost(int baselineNumber) { return ((Number) getCachedValue(selectField(AssignmentFieldLists.BASELINE_COSTS, baselineNumber))); } /** * Set a baseline value. * * @param baselineNumber baseline index (1-10) * @param value baseline value */ public void setBaselineStart(int baselineNumber, Date value) { set(selectField(AssignmentFieldLists.BASELINE_STARTS, baselineNumber), value); } /** * Retrieve a baseline value. * * @param baselineNumber baseline index (1-10) * @return baseline value */ public Date getBaselineStart(int baselineNumber) { return (Date) getCachedValue(selectField(AssignmentFieldLists.BASELINE_STARTS, baselineNumber)); } /** * Set a baseline value. * * @param baselineNumber baseline index (1-10) * @param value baseline value */ public void setBaselineFinish(int baselineNumber, Date value) { set(selectField(AssignmentFieldLists.BASELINE_FINISHES, baselineNumber), value); } /** * Retrieve a baseline value. * * @param baselineNumber baseline index (1-10) * @return baseline value */ public Date getBaselineFinish(int baselineNumber) { return (Date) getCachedValue(selectField(AssignmentFieldLists.BASELINE_FINISHES, baselineNumber)); } /** * Set a baseline value. * * @param baselineNumber baseline index (1-10) * @param value baseline value */ public void setBaselineBudgetCost(int baselineNumber, Number value) { set(selectField(AssignmentFieldLists.BASELINE_BUDGET_COSTS, baselineNumber), value); } /** * Set a baseline value. * * @param baselineNumber baseline index (1-10) * @param value baseline value */ public void setBaselineBudgetWork(int baselineNumber, Duration value) { set(selectField(AssignmentFieldLists.BASELINE_BUDGET_WORKS, baselineNumber), value); } /** * Retrieve a baseline value. * * @param baselineNumber baseline index (1-10) * @return baseline value */ public Duration getBaselineBudgetWork(int baselineNumber) { return ((Duration) getCachedValue(selectField(AssignmentFieldLists.BASELINE_BUDGET_WORKS, baselineNumber))); } /** * Retrieve a baseline value. * * @param baselineNumber baseline index (1-10) * @return baseline value */ public Number getBaselineBudgetCost(int baselineNumber) { return ((Number) getCachedValue(selectField(AssignmentFieldLists.BASELINE_BUDGET_COSTS, baselineNumber))); } /** * Set a text value. * * @param index text index (1-30) * @param value text value */ public void setText(int index, String value) { set(selectField(AssignmentFieldLists.CUSTOM_TEXT, index), value); } /** * Retrieve a text value. * * @param index text index (1-30) * @return text value */ public String getText(int index) { return (String) getCachedValue(selectField(AssignmentFieldLists.CUSTOM_TEXT, index)); } /** * Set a start value. * * @param index start index (1-10) * @param value start value */ public void setStart(int index, Date value) { set(selectField(AssignmentFieldLists.CUSTOM_START, index), value); } /** * Retrieve a start value. * * @param index start index (1-10) * @return start value */ public Date getStart(int index) { return (Date) getCachedValue(selectField(AssignmentFieldLists.CUSTOM_START, index)); } /** * Set a finish value. * * @param index finish index (1-10) * @param value finish value */ public void setFinish(int index, Date value) { set(selectField(AssignmentFieldLists.CUSTOM_FINISH, index), value); } /** * Retrieve a finish value. * * @param index finish index (1-10) * @return finish value */ public Date getFinish(int index) { return (Date) getCachedValue(selectField(AssignmentFieldLists.CUSTOM_FINISH, index)); } /** * Set a date value. * * @param index date index (1-10) * @param value date value */ public void setDate(int index, Date value) { set(selectField(AssignmentFieldLists.CUSTOM_DATE, index), value); } /** * Retrieve a date value. * * @param index date index (1-10) * @return date value */ public Date getDate(int index) { return (Date) getCachedValue(selectField(AssignmentFieldLists.CUSTOM_DATE, index)); } /** * Set a number value. * * @param index number index (1-20) * @param value number value */ public void setNumber(int index, Number value) { set(selectField(AssignmentFieldLists.CUSTOM_NUMBER, index), value); } /** * Retrieve a number value. * * @param index number index (1-20) * @return number value */ public Number getNumber(int index) { return (Number) getCachedValue(selectField(AssignmentFieldLists.CUSTOM_NUMBER, index)); } /** * Set a duration value. * * @param index duration index (1-10) * @param value duration value */ public void setDuration(int index, Duration value) { set(selectField(AssignmentFieldLists.CUSTOM_DURATION, index), value); } /** * Retrieve a duration value. * * @param index duration index (1-10) * @return duration value */ public Duration getDuration(int index) { return (Duration) getCachedValue(selectField(AssignmentFieldLists.CUSTOM_DURATION, index)); } /** * Set a cost value. * * @param index cost index (1-10) * @param value cost value */ public void setCost(int index, Number value) { set(selectField(AssignmentFieldLists.CUSTOM_COST, index), value); } /** * Retrieve a cost value. * * @param index cost index (1-10) * @return cost value */ public Number getCost(int index) { return (Number) getCachedValue(selectField(AssignmentFieldLists.CUSTOM_COST, index)); } /** * Set a flag value. * * @param index flag index (1-20) * @param value flag value */ public void setFlag(int index, boolean value) { set(selectField(AssignmentFieldLists.CUSTOM_FLAG, index), value); } /** * Retrieve a flag value. * * @param index flag index (1-20) * @return flag value */ public boolean getFlag(int index) { return BooleanHelper.getBoolean((Boolean) getCachedValue(selectField(AssignmentFieldLists.CUSTOM_FLAG, index))); } /** * Set an enterprise cost value. * * @param index cost index (1-30) * @param value cost value */ public void setEnterpriseCost(int index, Number value) { set(selectField(AssignmentFieldLists.ENTERPRISE_COST, index), value); } /** * Retrieve an enterprise cost value. * * @param index cost index (1-30) * @return cost value */ public Number getEnterpriseCost(int index) { return (Number) getCachedValue(selectField(AssignmentFieldLists.ENTERPRISE_COST, index)); } /** * Set an enterprise date value. * * @param index date index (1-30) * @param value date value */ public void setEnterpriseDate(int index, Date value) { set(selectField(AssignmentFieldLists.ENTERPRISE_DATE, index), value); } /** * Retrieve an enterprise date value. * * @param index date index (1-30) * @return date value */ public Date getEnterpriseDate(int index) { return (Date) getCachedValue(selectField(AssignmentFieldLists.ENTERPRISE_DATE, index)); } /** * Set an enterprise duration value. * * @param index duration index (1-30) * @param value duration value */ public void setEnterpriseDuration(int index, Duration value) { set(selectField(AssignmentFieldLists.ENTERPRISE_DURATION, index), value); } /** * Retrieve an enterprise duration value. * * @param index duration index (1-30) * @return duration value */ public Duration getEnterpriseDuration(int index) { return (Duration) getCachedValue(selectField(AssignmentFieldLists.ENTERPRISE_DURATION, index)); } /** * Set an enterprise flag value. * * @param index flag index (1-20) * @param value flag value */ public void setEnterpriseFlag(int index, boolean value) { set(selectField(AssignmentFieldLists.ENTERPRISE_FLAG, index), value); } /** * Retrieve an enterprise flag value. * * @param index flag index (1-20) * @return flag value */ public boolean getEnterpriseFlag(int index) { return BooleanHelper.getBoolean((Boolean) getCachedValue(selectField(AssignmentFieldLists.ENTERPRISE_FLAG, index))); } /** * Set an enterprise number value. * * @param index number index (1-40) * @param value number value */ public void setEnterpriseNumber(int index, Number value) { set(selectField(AssignmentFieldLists.ENTERPRISE_NUMBER, index), value); } /** * Retrieve an enterprise number value. * * @param index number index (1-40) * @return number value */ public Number getEnterpriseNumber(int index) { return (Number) getCachedValue(selectField(AssignmentFieldLists.ENTERPRISE_NUMBER, index)); } /** * Set an enterprise text value. * * @param index text index (1-40) * @param value text value */ public void setEnterpriseText(int index, String value) { set(selectField(AssignmentFieldLists.ENTERPRISE_TEXT, index), value); } /** * Retrieve an enterprise text value. * * @param index text index (1-40) * @return text value */ public String getEnterpriseText(int index) { return (String) getCachedValue(selectField(AssignmentFieldLists.ENTERPRISE_TEXT, index)); } /** * Retrieve an enterprise custom field value. * * @param index field index * @return field value */ public String getEnterpriseCustomField(int index) { return ((String) getCachedValue(selectField(AssignmentFieldLists.ENTERPRISE_CUSTOM_FIELD, index))); } /** * Set an enterprise custom field value. * * @param index field index * @param value field value */ public void setEnterpriseCustomField(int index, String value) { set(selectField(AssignmentFieldLists.ENTERPRISE_CUSTOM_FIELD, index), value); } /** * Returns the regular work of this resource assignment. * * @return work */ public Duration getRegularWork() { return ((Duration) getCachedValue(AssignmentField.REGULAR_WORK)); } /** * Sets the regular work for this resource assignment. * * @param dur work */ public void setRegularWork(Duration dur) { set(AssignmentField.REGULAR_WORK, dur); } /** * Returns the actual overtime work of this resource assignment. * * @return work */ public Duration getActualOvertimeWork() { return ((Duration) getCachedValue(AssignmentField.ACTUAL_OVERTIME_WORK)); } /** * Sets the actual overtime work for this resource assignment. * * @param dur work */ public void setActualOvertimeWork(Duration dur) { set(AssignmentField.ACTUAL_OVERTIME_WORK, dur); } /** * Returns the remaining overtime work of this resource assignment. * * @return work */ public Duration getRemainingOvertimeWork() { return ((Duration) getCachedValue(AssignmentField.REMAINING_OVERTIME_WORK)); } /** * Sets the remaining overtime work for this resource assignment. * * @param dur work */ public void setRemainingOvertimeWork(Duration dur) { set(AssignmentField.REMAINING_OVERTIME_WORK, dur); } /** * Returns the overtime cost of this resource assignment. * * @return cost */ public Number getOvertimeCost() { Number cost = (Number) getCachedValue(AssignmentField.OVERTIME_COST); if (cost == null) { Number actual = getActualOvertimeCost(); Number remaining = getRemainingOvertimeCost(); if (actual != null && remaining != null) { cost = NumberHelper.getDouble(actual.doubleValue() + remaining.doubleValue()); set(AssignmentField.OVERTIME_COST, cost); } } return (cost); } /** * Sets the overtime cost for this resource assignment. * * @param cost cost */ public void setOvertimeCost(Number cost) { set(AssignmentField.OVERTIME_COST, cost); } /** * Returns the remaining cost of this resource assignment. * * @return cost */ public Number getRemainingCost() { return ((Number) getCachedValue(AssignmentField.REMAINING_COST)); } /** * Sets the remaining cost for this resource assignment. * * @param cost cost */ public void setRemainingCost(Number cost) { set(AssignmentField.REMAINING_COST, cost); } /** * Returns the actual overtime cost of this resource assignment. * * @return cost */ public Number getActualOvertimeCost() { return ((Number) getCachedValue(AssignmentField.ACTUAL_OVERTIME_COST)); } /** * Sets the actual overtime cost for this resource assignment. * * @param cost cost */ public void setActualOvertimeCost(Number cost) { set(AssignmentField.ACTUAL_OVERTIME_COST, cost); } /** * Returns the remaining overtime cost of this resource assignment. * * @return cost */ public Number getRemainingOvertimeCost() { return ((Number) getCachedValue(AssignmentField.REMAINING_OVERTIME_COST)); } /** * Sets the remaining overtime cost for this resource assignment. * * @param cost cost */ public void setRemainingOvertimeCost(Number cost) { set(AssignmentField.REMAINING_OVERTIME_COST, cost); } /** * The BCWP (budgeted cost of work performed) field contains the * cumulative value * of the assignment's timephased percent complete multiplied by * the assignments * timephased baseline cost. BCWP is calculated up to the status * date or todays * date. This information is also known as earned value. * * @param val the amount to be set */ public void setBCWP(Number val) { set(AssignmentField.BCWP, val); } /** * The BCWP (budgeted cost of work performed) field contains * the cumulative value of the assignment's timephased percent complete * multiplied by the assignment's timephased baseline cost. * BCWP is calculated up to the status date or today's date. * This information is also known as earned value. * * @return currency amount as float */ public Number getBCWP() { return ((Number) getCachedValue(AssignmentField.BCWP)); } /** * The BCWS (budgeted cost of work scheduled) field contains the cumulative * timephased baseline costs up to the status date or today's date. * * @param val the amount to set */ public void setBCWS(Number val) { set(AssignmentField.BCWS, val); } /** * The BCWS (budgeted cost of work scheduled) field contains the cumulative * timephased baseline costs up to the status date or today's date. * * @return currency amount as float */ public Number getBCWS() { return ((Number) getCachedValue(AssignmentField.BCWS)); } /** * Retrieve the ACWP value. * * @return ACWP value */ public Number getACWP() { return ((Number) getCachedValue(AssignmentField.ACWP)); } /** * Set the ACWP value. * * @param acwp ACWP value */ public void setACWP(Number acwp) { set(AssignmentField.ACWP, acwp); } /** * The SV (earned value schedule variance) field shows the difference * in cost terms between the current progress and the baseline plan * of the task up to the status date or today's date. You can use SV * to check costs to determine whether tasks are on schedule. * @param val - currency amount */ public void setSV(Number val) { set(AssignmentField.SV, val); } /** * The SV (earned value schedule variance) field shows the difference in * cost terms between the current progress and the baseline plan of the * task up to the status date or today's date. You can use SV to * check costs to determine whether tasks are on schedule. * * @return -earned value schedule variance */ public Number getSV() { Number variance = (Number) getCachedValue(AssignmentField.SV); if (variance == null) { Number bcwp = getBCWP(); Number bcws = getBCWS(); if (bcwp != null && bcws != null) { variance = NumberHelper.getDouble(bcwp.doubleValue() - bcws.doubleValue()); set(AssignmentField.SV, variance); } } return (variance); } /** * The CV (earned value cost variance) field shows the difference * between how much it should have cost to achieve the current level of * completion on the task, and how much it has actually cost to achieve the * current level of completion up to the status date or today's date. * * @param val value to set */ public void setCV(Number val) { set(AssignmentField.CV, val); } /** * The CV (earned value cost variance) field shows the difference between * how much it should have cost to achieve the current level of completion * on the task, and how much it has actually cost to achieve the current * level of completion up to the status date or today's date. * How Calculated CV is the difference between BCWP * (budgeted cost of work performed) and ACWP * (actual cost of work performed). Microsoft Project calculates * the CV as follows: CV = BCWP - ACWP * * @return sum of earned value cost variance */ public Number getCV() { Number variance = (Number) getCachedValue(AssignmentField.CV); if (variance == null) { variance = Double.valueOf(NumberHelper.getDouble(getBCWP()) - NumberHelper.getDouble(getACWP())); set(AssignmentField.CV, variance); } return (variance); } /** * The Cost Variance field shows the difference between the * baseline cost and total cost for a task. The total cost is the * current estimate of costs based on actual costs and remaining costs. * This is also referred to as variance at completion (VAC). * * @param val amount */ public void setCostVariance(Number val) { set(AssignmentField.COST_VARIANCE, val); } /** * The Cost Variance field shows the difference between the baseline cost * and total cost for a task. The total cost is the current estimate of costs * based on actual costs and remaining costs. This is also referred to as * variance at completion (VAC). * * @return amount */ public Number getCostVariance() { Number variance = (Number) getCachedValue(AssignmentField.COST_VARIANCE); if (variance == null) { Number cost = getCost(); Number baselineCost = getBaselineCost(); if (cost != null && baselineCost != null) { variance = NumberHelper.getDouble(cost.doubleValue() - baselineCost.doubleValue()); set(AssignmentField.COST_VARIANCE, variance); } } return (variance); } /** * The % Work Complete field contains the current status of a task, * expressed as the * percentage of the task's work that has been completed. You can enter * percent work * complete, or you can have Microsoft Project calculate it for you * based on actual * work on the task. * * @param val value to be set */ public void setPercentageWorkComplete(Number val) { set(AssignmentField.PERCENT_WORK_COMPLETE, val); } /** * The % Work Complete field contains the current status of a task, * expressed as the percentage of the task's work that has been completed. * You can enter percent work complete, or you can have Microsoft Project * calculate it for you based on actual work on the task. * * @return percentage as float */ public Number getPercentageWorkComplete() { Number pct = (Number) getCachedValue(AssignmentField.PERCENT_WORK_COMPLETE); if (pct == null) { Duration actualWork = getActualWork(); Duration work = getWork(); if (actualWork != null && work != null && work.getDuration() != 0) { pct = Double.valueOf((actualWork.getDuration() * 100) / work.convertUnits(actualWork.getUnits(), getParentFile().getProjectProperties()).getDuration()); set(AssignmentField.PERCENT_WORK_COMPLETE, pct); } } return pct; } /** * This method is used to add notes to the current task. * * @param notes notes to be added */ public void setNotes(String notes) { set(AssignmentField.NOTES, notes); } /** * The Notes field contains notes that you can enter about a task. * You can use task notes to help maintain a history for a task. * * @return notes */ public String getNotes() { String notes = (String) getCachedValue(AssignmentField.NOTES); return (notes == null ? "" : notes); } /** * The Confirmed field indicates whether all resources assigned to a task have * accepted or rejected the task assignment in response to a TeamAssign message * regarding their assignments. * * @param val boolean value */ public void setConfirmed(boolean val) { set(AssignmentField.CONFIRMED, val); } /** * The Confirmed field indicates whether all resources assigned to a task * have accepted or rejected the task assignment in response to a TeamAssign * message regarding their assignments. * * @return boolean */ public boolean getConfirmed() { return (BooleanHelper.getBoolean((Boolean) getCachedValue(AssignmentField.CONFIRMED))); } /** * The Update Needed field indicates whether a TeamUpdate message should * be sent to the assigned resources because of changes to the start date, * finish date, or resource reassignments of the task. * * @param val - boolean */ public void setUpdateNeeded(boolean val) { set(AssignmentField.UPDATE_NEEDED, val); } /** * The Update Needed field indicates whether a TeamUpdate message * should be sent to the assigned resources because of changes to the * start date, finish date, or resource reassignments of the task. * * @return true if needed. */ public boolean getUpdateNeeded() { return (BooleanHelper.getBoolean((Boolean) getCachedValue(AssignmentField.UPDATE_NEEDED))); } /** * The Linked Fields field indicates whether there are OLE links to the task, * either from elsewhere in the active project, another Microsoft Project * file, or from another program. * * @param flag boolean value */ public void setLinkedFields(boolean flag) { set(AssignmentField.LINKED_FIELDS, flag); } /** * The Linked Fields field indicates whether there are OLE links to the task, * either from elsewhere in the active project, another Microsoft Project file, * or from another program. * * @return boolean */ public boolean getLinkedFields() { return (BooleanHelper.getBoolean((Boolean) getCachedValue(AssignmentField.LINKED_FIELDS))); } /** * Retrieves the task hyperlink attribute. * * @return hyperlink attribute */ public String getHyperlink() { return ((String) getCachedValue(AssignmentField.HYPERLINK)); } /** * Retrieves the task hyperlink address attribute. * * @return hyperlink address attribute */ public String getHyperlinkAddress() { return ((String) getCachedValue(AssignmentField.HYPERLINK_ADDRESS)); } /** * Retrieves the task hyperlink sub-address attribute. * * @return hyperlink sub address attribute */ public String getHyperlinkSubAddress() { return ((String) getCachedValue(AssignmentField.HYPERLINK_SUBADDRESS)); } /** * Sets the task hyperlink attribute. * * @param text hyperlink attribute */ public void setHyperlink(String text) { set(AssignmentField.HYPERLINK, text); } /** * Sets the task hyperlink address attribute. * * @param text hyperlink address attribute */ public void setHyperlinkAddress(String text) { set(AssignmentField.HYPERLINK_ADDRESS, text); } /** * Sets the task hyperlink sub address attribute. * * @param text hyperlink sub address attribute */ public void setHyperlinkSubAddress(String text) { set(AssignmentField.HYPERLINK_SUBADDRESS, text); } /** * The Work Variance field contains the difference between a task's baseline * work and the currently scheduled work. * * @param val - duration */ public void setWorkVariance(Duration val) { set(AssignmentField.WORK_VARIANCE, val); } /** * The Work Variance field contains the difference between a task's * baseline work and the currently scheduled work. * * @return Duration representing duration. */ public Duration getWorkVariance() { Duration variance = (Duration) getCachedValue(AssignmentField.WORK_VARIANCE); if (variance == null) { Duration work = getWork(); Duration baselineWork = getBaselineWork(); if (work != null && baselineWork != null) { variance = Duration.getInstance(work.getDuration() - baselineWork.convertUnits(work.getUnits(), getParentFile().getProjectProperties()).getDuration(), work.getUnits()); set(AssignmentField.WORK_VARIANCE, variance); } } return (variance); } /** * The Start Variance field contains the amount of time that represents the * difference between a task's baseline start date and its currently * scheduled start date. * * @param val - duration */ public void setStartVariance(Duration val) { set(AssignmentField.START_VARIANCE, val); } /** * Calculate the start variance. * * @return start variance */ public Duration getStartVariance() { Duration variance = (Duration) getCachedValue(AssignmentField.START_VARIANCE); if (variance == null) { TimeUnit format = getParentFile().getProjectProperties().getDefaultDurationUnits(); variance = DateHelper.getVariance(getTask(), getBaselineStart(), getStart(), format); set(AssignmentField.START_VARIANCE, variance); } return (variance); } /** * The Finish Variance field contains the amount of time that represents the * difference between a task's baseline finish date and its forecast * or actual finish date. * * @param duration duration value */ public void setFinishVariance(Duration duration) { set(AssignmentField.FINISH_VARIANCE, duration); } /** * Calculate the finish variance. * * @return finish variance */ public Duration getFinishVariance() { Duration variance = (Duration) getCachedValue(AssignmentField.FINISH_VARIANCE); if (variance == null) { TimeUnit format = getParentFile().getProjectProperties().getDefaultDurationUnits(); variance = DateHelper.getVariance(getTask(), getBaselineFinish(), getFinish(), format); set(AssignmentField.FINISH_VARIANCE, variance); } return (variance); } /** * The Created field contains the date and time when a task was added * to the project. * * @return Date */ public Date getCreateDate() { return ((Date) getCachedValue(AssignmentField.CREATED)); } /** * The Created field contains the date and time when a task was * added to the project. * * @param val date */ public void setCreateDate(Date val) { set(AssignmentField.CREATED, val); } /** * Retrieve the task GUID. * * @return task GUID */ public UUID getGUID() { return (UUID) getCachedValue(AssignmentField.GUID); } /** * Set the task GUID. * * @param value task GUID */ public void setGUID(UUID value) { set(AssignmentField.GUID, value); } /** * Sets a flag to indicate if a response has been received from a resource * assigned to a task. * * @param val boolean value */ public void setResponsePending(boolean val) { set(AssignmentField.RESPONSE_PENDING, val); } /** * Retrieves a flag to indicate if a response has been received from a resource * assigned to a task. * * @return boolean value */ public boolean getResponsePending() { return (BooleanHelper.getBoolean((Boolean) getCachedValue(AssignmentField.RESPONSE_PENDING))); } /** * Sets a flag to indicate if a response has been received from a resource * assigned to a task. * * @param val boolean value */ public void setTeamStatusPending(boolean val) { set(AssignmentField.TEAM_STATUS_PENDING, val); } /** * Retrieves a flag to indicate if a response has been received from a resource * assigned to a task. * * @return boolean value */ public boolean getTeamStatusPending() { return (BooleanHelper.getBoolean((Boolean) getCachedValue(AssignmentField.TEAM_STATUS_PENDING))); } /** * Sets VAC for this resource assignment. * * @param value VAC value */ public void setVAC(Number value) { set(AssignmentField.VAC, value); } /** * Returns the VAC for this resource assignment. * * @return VAC value */ public Number getVAC() { return ((Number) getCachedValue(AssignmentField.VAC)); } /** * Sets the index of the cost rate table for this assignment. * * @param index cost rate table index */ public void setCostRateTableIndex(int index) { set(AssignmentField.COST_RATE_TABLE, Integer.valueOf(index)); } /** * Returns the cost rate table index for this assignment. * * @return cost rate table index */ public int getCostRateTableIndex() { Integer value = (Integer) getCachedValue(AssignmentField.COST_RATE_TABLE); return value == null ? 0 : value.intValue(); } /** * Returns the cost rate table for this assignment. * * @return cost rate table index */ public CostRateTable getCostRateTable() { return getResource() == null ? null : getResource().getCostRateTable(getCostRateTableIndex()); } /** * Retrieves the hyperlink screen tip attribute. * * @return hyperlink screen tip attribute */ public String getHyperlinkScreenTip() { return ((String) getCachedValue(AssignmentField.HYPERLINK_SCREEN_TIP)); } /** * Sets the hyperlink screen tip attribute. * * @param text hyperlink screen tip attribute */ public void setHyperlinkScreenTip(String text) { set(AssignmentField.HYPERLINK_SCREEN_TIP, text); } /** * Retrieves the resource request type attribute. * * @return resource request type */ public ResourceRequestType getResourceRequestType() { return (ResourceRequestType) getCachedValue(AssignmentField.RESOURCE_REQUEST_TYPE); } /** * Sets the resource request type attribute. * * @param type resource request type */ public void setResourceRequestType(ResourceRequestType type) { set(AssignmentField.RESOURCE_REQUEST_TYPE, type); } /** * Maps a field index to an AssignmentField instance. * * @param fields array of fields used as the basis for the mapping. * @param index required field index * @return AssignmnetField instance */ private AssignmentField selectField(AssignmentField[] fields, int index) { if (index < 1 || index > fields.length) { throw new IllegalArgumentException(index + " is not a valid field index"); } return (fields[index - 1]); } /** * {@inheritDoc} */ @Override public String toString() { return ("[Resource Assignment task=" + getTask().getName() + " resource=" + (getResource() == null ? "Unassigned" : getResource().getName()) + " start=" + getStart() + " finish=" + getFinish() + " duration=" + getWork() + " workContour=" + getWorkContour() + "]"); } /** * {@inheritDoc} */ @Override public void set(FieldType field, Object value) { if (field != null) { int index = field.getValue(); if (m_eventsEnabled) { fireFieldChangeEvent((AssignmentField) field, m_array[index], value); } m_array[index] = value; } } /** * This method inserts a name value pair into internal storage. * * @param field task field * @param value attribute value */ private void set(FieldType field, boolean value) { set(field, (value ? Boolean.TRUE : Boolean.FALSE)); } /** * Handle the change in a field value. Reset any cached calculated * values affected by this change, pass on the event to any external * listeners. * * @param field field changed * @param oldValue old field value * @param newValue new field value */ private void fireFieldChangeEvent(AssignmentField field, Object oldValue, Object newValue) { // // Internal event handling // switch (field) { case START: case BASELINE_START: { m_array[AssignmentField.START_VARIANCE.getValue()] = null; break; } case FINISH: case BASELINE_FINISH: { m_array[AssignmentField.FINISH_VARIANCE.getValue()] = null; break; } case BCWP: case ACWP: { m_array[AssignmentField.CV.getValue()] = null; m_array[AssignmentField.SV.getValue()] = null; break; } case COST: case BASELINE_COST: { m_array[AssignmentField.COST_VARIANCE.getValue()] = null; break; } case WORK: case BASELINE_WORK: { m_array[AssignmentField.WORK_VARIANCE.getValue()] = null; break; } case ACTUAL_OVERTIME_COST: case REMAINING_OVERTIME_COST: { m_array[AssignmentField.OVERTIME_COST.getValue()] = null; break; } default: { break; } } // // External event handling // if (m_listeners != null) { for (FieldListener listener : m_listeners) { listener.fieldChange(this, field, oldValue, newValue); } } } /** * {@inheritDoc} */ @Override public void addFieldListener(FieldListener listener) { if (m_listeners == null) { m_listeners = new LinkedList<FieldListener>(); } m_listeners.add(listener); } /** * {@inheritDoc} */ @Override public void removeFieldListener(FieldListener listener) { if (m_listeners != null) { m_listeners.remove(listener); } } /** * {@inheritDoc} */ @Override public Object getCachedValue(FieldType field) { return (field == null ? null : m_array[field.getValue()]); } /** * {@inheritDoc} */ @Override public Object getCurrentValue(FieldType field) { Object result = null; if (field != null) { int fieldValue = field.getValue(); result = m_array[fieldValue]; } return (result); } /** * Disable events firing when fields are updated. */ public void disableEvents() { m_eventsEnabled = false; } /** * Enable events firing when fields are updated. This is the default state. */ public void enableEvents() { m_eventsEnabled = true; } /** * Array of field values. */ private Object[] m_array = new Object[AssignmentField.MAX_VALUE]; private boolean m_eventsEnabled = true; private DefaultTimephasedWorkContainer m_timephasedWork; private List<TimephasedCost> m_timephasedCost; private TimephasedWorkContainer m_timephasedActualWork; private List<TimephasedCost> m_timephasedActualCost; private TimephasedWorkContainer m_timephasedOvertimeWork; private TimephasedWorkContainer m_timephasedActualOvertimeWork; private List<FieldListener> m_listeners; private TimephasedWorkContainer[] m_timephasedBaselineWork = new TimephasedWorkContainer[11]; private TimephasedCostContainer[] m_timephasedBaselineCost = new TimephasedCostContainer[11]; /** * Reference to the parent task of this assignment. */ private Task m_task; /** * Child record for Workgroup fields. */ private ResourceAssignmentWorkgroupFields m_workgroup; /** * Default units value: 100%. */ public static final Double DEFAULT_UNITS = Double.valueOf(100); }