This class holds the work related bits of a time sheet that are specific to a single Task. This can be an existing Task or a new one identified by it’s ID String. For effort based task, it stores the remaining effort, for other task the expected end date. For all tasks it stores the completed work during the reporting time frame.
# File lib/taskjuggler/TimeSheets.rb, line 27 27: def initialize(timeSheet, task) 28: # This is a reference to a Task object for existing tasks or an ID as 29: # String for new tasks. 30: @task = task 31: # Add the new TimeSheetRecord to the TimeSheet it belongs to. 32: (@timeSheet = timeSheet) << self 33: # Work done will be measured in time slots. 34: @work = nil 35: # Remaining work will be measured in time slots. 36: @remaining = nil 37: @expectedEnd = nil 38: # For new task, we also need to store the name. 39: @name = nil 40: # Reference to the JournalEntry object that holds the status for this 41: # record. 42: @status = nil 43: @priority = 0 44: @sourceFileInfo = nil 45: end
The reported expected end of the task.
# File lib/taskjuggler/TimeSheets.rb, line 224 224: def actualEnd 225: @expectedEnd 226: end
The reporting remaining effort in days.
# File lib/taskjuggler/TimeSheets.rb, line 208 208: def actualRemaining 209: project = @timeSheet.resource.project 210: project.convertToDailyLoad(@remaining * project['scheduleGranularity']) 211: end
The reported work in % (0.0 - 100.0) of the average working time.
# File lib/taskjuggler/TimeSheets.rb, line 191 191: def actualWorkPercent 192: (@work.to_f / @timeSheet.totalGrossWorkingSlots) * 100.0 193: end
Perform all kinds of consistency checks.
# File lib/taskjuggler/TimeSheets.rb, line 60 60: def check 61: scIdx = @timeSheet.scenarioIdx 62: taskId = @task.is_a?(Task) ? @task.fullId : @task 63: # All TimeSheetRecords must have a 'work' attribute. 64: if @work.nil? 65: error('ts_no_work', 66: "The time sheet record for task #{taskId} must " + 67: "have a 'work' attribute to specify how much was done " + 68: "for this task during the reported period.") 69: end 70: if @task.is_a?(Task) 71: # This is already known tasks. 72: if @task['effort', scIdx] > 0 73: unless @remaining 74: error('ts_no_remaining', 75: "The time sheet record for task #{taskId} must " + 76: "have a 'remaining' attribute to specify how much " + 77: "effort is left for this task.") 78: end 79: else 80: unless @expectedEnd 81: error('ts_no_expected_end', 82: "The time sheet record for task #{taskId} must " + 83: "have an 'end' attribute to specify the expected end " + 84: "of this task.") 85: end 86: end 87: else 88: # This is for new tasks. 89: if @remaining.nil? && @expectedEnd.nil? 90: error('ts_no_rem_or_end', 91: "New task #{taskId} requires either a 'remaining' or a " + 92: "'end' attribute.") 93: end 94: end 95: 96: if @work >= @timeSheet.daysToSlots(1) && @status.nil? 97: error('ts_no_status_work', 98: "You must specify a status for task #{taskId}.") 99: end 100: 101: if @status 102: if @status.headline.empty? 103: error('ts_no_headline', 104: "You must provide a headline for the status of " + 105: "task #{@task.fullId}") 106: end 107: if @status.summary && 108: @status.summary.richText.inputText == "A summary text\n" 109: error('ts_default_summary', 110: "You must change the default summary text of the status " + 111: "for task #{taskId}.") 112: end 113: if @status.alertLevel > 0 && @status.summary.nil? && 114: @status.details.nil? 115: error('ts_alert1_more_details', 116: "Task #{taskId} has an elevated alert level and must " + 117: "have a summary or details section.") 118: end 119: if @status.alertLevel > 1 && @status.details.nil? 120: error('ts_alert2_more_details', 121: "Task #{taskId} has a high alert level and must have " + 122: "a details section.") 123: end 124: end 125: end
The planned end of the task.
# File lib/taskjuggler/TimeSheets.rb, line 229 229: def planEnd 230: @task['end', @timeSheet.scenarioIdx] 231: end
The remaining effort according to the plan.
# File lib/taskjuggler/TimeSheets.rb, line 214 214: def planRemaining 215: resource = @timeSheet.resource 216: project = resource.project 217: scenarioIdx = @timeSheet.scenarioIdx 218: startIdx = project.dateToIdx(project['now']) 219: endIdx = project.dateToIdx(@task['end', scenarioIdx]) 220: @task.getEffectiveWork(scenarioIdx, startIdx, endIdx, resource) 221: end
The planned work in % (0.0 - 100.0) of the average working time.
# File lib/taskjuggler/TimeSheets.rb, line 196 196: def planWorkPercent 197: resource = @timeSheet.resource 198: project = resource.project 199: scenarioIdx = @timeSheet.scenarioIdx 200: startIdx = project.dateToIdx(@timeSheet.interval.start) 201: endIdx = project.dateToIdx(@timeSheet.interval.end) 202: (@timeSheet.resource.getAllocatedSlots(scenarioIdx, startIdx, endIdx, 203: @task).to_f / 204: @timeSheet.totalGrossWorkingSlots) * 100.0 205: end
# File lib/taskjuggler/TimeSheets.rb, line 186 186: def taskId 187: @task.is_a?(Task) ? @task.fullId : task 188: end
# File lib/taskjuggler/TimeSheets.rb, line 127 127: def warnOnDelta(startIdx, endIdx) 128: # Ignore personal entries. 129: return unless @task 130: 131: resource = @timeSheet.resource 132: if @task.is_a?(String) 133: # A resource has requested a new Task to be created. 134: warning('ts_res_new_task', 135: "#{resource.name} is requesting a new task:\n" + 136: " ID: #{@task}\n" + 137: " Name: #{@name}\n" + 138: " Work: #{@timeSheet.slotsToDays(@work)}d " + 139: (@remaining ? 140: "Remaining: #{@timeSheet.slotsToDays(@remaining)}d" : 141: "End: #{@end.to_s}")) 142: return 143: end 144: 145: scenarioIdx = @timeSheet.scenarioIdx 146: project = resource.project 147: plannedWork = @task.getEffectiveWork(scenarioIdx, startIdx, endIdx, 148: resource) 149: # Convert the @work slots into a daily load. 150: work = project.convertToDailyLoad(@work * project['scheduleGranularity']) 151: 152: if work != plannedWork 153: warning('ts_res_work_delta', 154: "#{resource.name} worked " + 155: "#{work < plannedWork ? 'less' : 'more'} " + 156: "on #{@task.fullId}\n" + 157: "#{work}d instead of #{plannedWork}d") 158: end 159: if @task['effort', scenarioIdx] > 0 160: startIdx = endIdx 161: endIdx = project.dateToIdx(@task['end', scenarioIdx]) 162: remainingWork = @task.getEffectiveWork(scenarioIdx, startIdx, endIdx, 163: resource) 164: # Convert the @remaining slots into a daily load. 165: remaining = project.convertToDailyLoad(@remaining * 166: project['scheduleGranularity']) 167: if remaining != remainingWork 168: warning('ts_res_remain_delta', 169: "#{resource.name} requests " + 170: "#{remaining < remainingWork ? 'less' : 'more'} " + 171: "remaining effort for task #{@task.fullId}\n" + 172: "#{remaining}d instead of #{remainingWork}d") 173: end 174: else 175: if @expectedEnd != @task['end', scenarioIdx] 176: warning('ts_res_end_delta', 177: "#{resource.name} requests " + 178: "#{@expectedEnd < @task['end', scenarioIdx] ? 179: 'earlier' : 'later'} end (#{@expectedEnd}) for task " + 180: "#{@task.fullId}. Planned end is " + 181: "#{@task['end', scenarioIdx]}.") 182: end 183: end 184: end
Store the number of worked time slots. If the value is a Fixnum, it can be directly assigned. A Float is interpreted as percentage and must be in the rage of 0.0 to 1.0.
# File lib/taskjuggler/TimeSheets.rb, line 50 50: def work=(value) 51: if value.is_a?(Fixnum) 52: @work = value 53: else 54: # Must be percent value 55: @work = @timeSheet.percentToSlots(value) 56: end 57: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.