diff --git a/app/models/deliverable.rb b/app/models/deliverable.rb
index 6e7f49d..fe117f0 100644
--- a/app/models/deliverable.rb
+++ b/app/models/deliverable.rb
@@ -85,9 +85,8 @@ class Deliverable < ActiveRecord::Base
end
# Total number of hours estimated in the Deliverable's budgets
- def estimated_hour_budget_total
- (labor_budgets.sum(:hours) || 0.0) +
- (overhead_budgets.sum(:hours) || 0.0)
+ def estimated_hour_budget_total(date=nil)
+ labor_budget_hours(date) + overhead_budget_hours(date)
end
# OPTIMIZE: N+1
@@ -100,9 +99,11 @@ class Deliverable < ActiveRecord::Base
issues.inject(0) {|total, issue| total += issue.overhead_time_spent } # From redmine_overhead
end
- # OPTIMIZE: N+1
- def hours_spent_total
- issues.inject(0) {|total, issue| total += issue.spent_hours }
+ def hours_spent_total(date=nil)
+ return 0 if issues.empty?
+
+ # Don't count subissues
+ TimeEntry.sum(:hours, :conditions => { :issue_id => issues.collect(&:id) })
end
def fixed_budget_total(date=nil)
diff --git a/app/models/retainer_deliverable.rb b/app/models/retainer_deliverable.rb
index 3cfb750..4517f2f 100644
--- a/app/models/retainer_deliverable.rb
+++ b/app/models/retainer_deliverable.rb
@@ -159,6 +159,23 @@ class RetainerDeliverable < HourlyDeliverable
end
end
+ def hours_spent_total(date=nil)
+ case scope_date_status(date)
+ when :in
+ return 0 if issues.empty?
+
+ TimeEntry.sum(:hours, :conditions => {
+ :issue_id => issues.collect(&:id),
+ :tyear => date.year,
+ :tmonth => date.month
+ })
+ when :out
+ 0
+ else
+ super
+ end
+ end
+
def fixed_budget_total(date=nil)
case scope_date_status(date)
when :in
diff --git a/app/views/deliverables/_details_row.html.erb b/app/views/deliverables/_details_row.html.erb
index eb8925c..c15974c 100644
--- a/app/views/deliverables/_details_row.html.erb
+++ b/app/views/deliverables/_details_row.html.erb
@@ -96,7 +96,11 @@
Total: |
<%= h(format_value_field_for_contracts(deliverable.total_spent(validated_period))) %> |
<%= h(format_value_field_for_contracts(deliverable.total(validated_period))) %> |
- TODO: Release 2 |
+
+
+ <%= h(format_value_field_for_contracts(deliverable.hours_spent_total(validated_period))) %>/<%= h(format_value_field_for_contracts(deliverable.estimated_hour_budget_total(validated_period))) %> <%= l(:text_short_hours) %>
+
+ |
diff --git a/test/integration/contracts_show_test.rb b/test/integration/contracts_show_test.rb
index 48d7387..2129c7c 100644
--- a/test/integration/contracts_show_test.rb
+++ b/test/integration/contracts_show_test.rb
@@ -348,6 +348,50 @@ class ContractsShowTest < ActionController::IntegrationTest
end
end
+
+ should "show the total hours for the deliverable" do
+ configure_overhead_plugin
+
+ @manager = User.generate!
+
+ @deliverable1 = FixedDeliverable.generate!(:contract => @contract, :manager => @manager)
+ LaborBudget.generate!(:deliverable => @deliverable1,
+ :hours => 100,
+ :budget => 4000.5)
+ OverheadBudget.generate!(:deliverable => @deliverable1,
+ :hours => 100,
+ :budget => 4000.5)
+
+ @issue1 = Issue.generate_for_project!(@project)
+ @time_entry1 = TimeEntry.generate!(:issue => @issue1,
+ :project => @project,
+ :activity => @billable_activity,
+ :spent_on => Date.today,
+ :hours => 10,
+ :user => @manager)
+ @time_entry2 = TimeEntry.generate!(:issue => @issue1,
+ :project => @project,
+ :activity => @non_billable_activity,
+ :spent_on => Date.today,
+ :hours => 5,
+ :user => @manager)
+
+ @rate = Rate.generate!(:project => @project,
+ :user => @manager,
+ :date_in_effect => Date.yesterday,
+ :amount => 100)
+
+ @deliverable1.issues << @issue1
+
+ assert_equal 1, @deliverable1.issues.count
+
+ visit_contract_page(@contract)
+ assert_select "table#deliverables" do
+ assert_select "td.total_hours", :text => /15\/200/
+ end
+
+ end
+
should "show the current period for a Retainer" do
today_mock = Date.new(2010,2,15)
diff --git a/test/unit/retainer_deliverable_test.rb b/test/unit/retainer_deliverable_test.rb
index f3e68c3..e966a0e 100644
--- a/test/unit/retainer_deliverable_test.rb
+++ b/test/unit/retainer_deliverable_test.rb
@@ -296,6 +296,66 @@ class RetainerDeliverableTest < ActiveSupport::TestCase
end
end
+ context "#hours_spent_total" do
+ setup do
+ @project = Project.generate!
+ @contract = Contract.generate!(:billable_rate => 100, :project => @project)
+ @deliverable = RetainerDeliverable.generate!(:start_date => '2010-01-01', :end_date => '2010-03-31', :contract => @contract)
+
+ @manager = User.generate!
+ @role = Role.generate!
+ User.add_to_project(@manager, @project, @role)
+
+ configure_overhead_plugin
+
+ @issue1 = Issue.generate_for_project!(@project)
+ @time_entry1 = TimeEntry.generate!(:issue => @issue1,
+ :project => @project,
+ :activity => @billable_activity,
+ :spent_on => Date.new(2010,1,2),
+ :hours => 10,
+ :user => @manager)
+ @time_entry2 = TimeEntry.generate!(:issue => @issue1,
+ :project => @project,
+ :activity => @non_billable_activity,
+ :spent_on => Date.new(2010,2,1),
+ :hours => 20,
+ :user => @manager)
+
+ @rate = Rate.generate!(:project => @project,
+ :user => @manager,
+ :date_in_effect => Date.new(2010,1,1),
+ :amount => 100)
+
+ @deliverable.issues << @issue1
+ assert_equal 30, @deliverable.hours_spent_total
+ end
+
+ context "with a empty period" do
+ should "use all periods" do
+ assert_equal 30.0, @deliverable.hours_spent_total(nil)
+ end
+ end
+
+ context "with a period out of the retainer range" do
+ should "filter the records" do
+ assert_equal 0, @deliverable.hours_spent_total(Date.new(2011,1,1))
+ end
+ end
+
+ context "with an invalid period" do
+ should "return 0" do
+ assert_equal 0, @deliverable.hours_spent_total('1')
+ end
+ end
+
+ context "with a period in the retainer range" do
+ should "filter the records" do
+ assert_equal 20.0, @deliverable.hours_spent_total(Date.new(2010,2,1))
+ end
+ end
+ end
+
context "#overhead_spent" do
setup do
@project = Project.generate!