lib/taskjuggler/ResourceScenario.rb in taskjuggler-3.5.0 vs lib/taskjuggler/ResourceScenario.rb in taskjuggler-3.6.0
- old
+ new
@@ -1,12 +1,12 @@
#!/usr/bin/env ruby -w
# encoding: UTF-8
#
# = ResourceScenario.rb -- The TaskJuggler III Project Management Software
#
-# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
-# by Chris Schlaeger <chris@linux.com>
+# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014
+# by Chris Schlaeger <cs@taskjuggler.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.
#
@@ -24,18 +24,11 @@
# nil: Value has not been determined yet.
# Task: A reference to a Task object
# Bit 0: Reserved
# Bit 1: 0: Work time (as defined by working hours)
# 1: No work time (as defined by working hours)
- # Bit 2 - 5: 0: No holiday or leave time
- # 1: Public holiday (holiday)
- # 2: Annual leave
- # 3: Special leave
- # 4: Sick leave
- # 5: unpaid leave
- # 6: blocked for other projects
- # 7 - 15: Reserved
+ # Bit 2 - 5: See Leave class for acutal values.
# Bit 6 - 7: Reserved
# Bit 8: 0: No global override
# 1: Override global setting
# The scoreboard is only created when needed to save memory for projects
# which read-in the coporate employee database but only need a small
@@ -71,12 +64,10 @@
# This method must be called at the beginning of each scheduling run. It
# initializes variables used during the scheduling process.
def prepareScheduling
@effort = 0
initScoreboard if @property.leaf?
-
- setDirectReports
end
# The criticalness of a resource is a measure for the probabilty that all
# allocations can be fullfilled. The smaller the value, the more likely
# will the tasks get the resource. A value above 1.0 means that
@@ -95,21 +86,39 @@
@alloctdeffort / freeSlots
end
end
def setDirectReports
- # Only leaf resources have reporting lines.
- return unless @property.leaf?
+ @managers.map! do |managerId|
+ # First we need to map 'managerId' to an existing Resource.
+ if (manager = @project.resource(managerId)).nil?
+ error('resource_id_expected', "#{managerId} is not a defined " +
+ 'resource.', @sourceFileInfo)
+ end
+ unless manager.leaf?
+ error('manager_is_group',
+ "Resource #{@property.fullId} has group #{manager.fullId} " +
+ "assigned as manager. Managers must be leaf resources.")
+ end
+ if manager == @property
+ error('manager_is_self',
+ "Resource #{@property.fullId} cannot manage itself.")
+ end
- # The 'directreports' attribute is the reverse link for the 'managers'
- # attribute. In contrast to the 'managers' attribute, the
- # 'directreports' list has no duplicate entries.
- @managers.each do |manager|
- unless manager['directreports', @scenarioIdx].include?(@property)
- manager['directreports', @scenarioIdx] << @property
+ # Only leaf resources have reporting lines.
+ if @property.leaf?
+ # The 'directreports' attribute is the reverse link for the 'managers'
+ # attribute. In contrast to the 'managers' attribute, the
+ # 'directreports' list has no duplicate entries.
+ unless manager['directreports', @scenarioIdx].include?(@property)
+ manager['directreports', @scenarioIdx] << @property
+ end
end
+
+ manager
end
+ @managers.uniq!
end
def setReports
return unless @directreports.empty?
@@ -117,21 +126,10 @@
r.setReports_i(@scenarioIdx, [ @property ])
end
end
def preScheduleCheck
- @managers.each do |manager|
- unless manager.leaf?
- error('manager_is_group',
- "Resource #{@property.fullId} has group #{manager.fullId} " +
- "assigned as manager. Managers must be leaf resources.")
- end
- if manager == @property
- error('manager_is_self',
- "Resource #{@property.fullId} cannot manage itself.")
- end
- end
end
# This method does some housekeeping work after the scheduling is
# completed. It's meant to be called for top-level resources and then
# recursively descends into all child resources.
@@ -385,11 +383,15 @@
@property.kids.each do |resource|
resource.query_headcount(@scenarioIdx, query)
headcount += query.to_num
end
else
- headcount += @efficiency.round
+ if employed?(@project.dateToIdx(query.start))
+ # We only count headcount that is employed at the start date of the
+ # query interval.
+ headcount += @efficiency.round
+ end
end
query.sortable = query.numerical = headcount
query.string = query.numberFormat.format(headcount)
end
@@ -890,9 +892,19 @@
if @shifts && @shifts.assigned?(sbIdx)
return @shifts.onShift?(sbIdx)
else
@workinghours.onShift?(sbIdx)
end
+ end
+
+ def employed?(sbIdx)
+ initScoreboard unless @scoreboard
+
+ val = @scoreboard[sbIdx]
+ return true unless val.is_a?(Fixnum)
+
+ leave_type = (val >> 2) & 0xF
+ leave_type < Leave::Types[:unemployed]
end
# Returns true if the resource or any of its children is allocated during
# the period specified with _startIdx_ and _endIdx_. If task is not nil
# only allocations to this tasks are respected.