diff --git a/app/models/deliverable.rb b/app/models/deliverable.rb
index 554efd1..d1fa66f 100644
--- a/app/models/deliverable.rb
+++ b/app/models/deliverable.rb
@@ -279,32 +279,44 @@ class Deliverable < ActiveRecord::Base
end
# Total amount spent ($) for a given activity
- def spent_for_activity(activity)
+ def spent_for_activity(activity, options={})
+ period = options[:period] || nil
issues.all.inject(0.0) do |all_issues_total, issue|
- all_issues_total += issue.time_entries.all(:conditions => {:activity_id => activity.id}).sum(&:cost)
+ conditions = ARCondition.new(["activity_id IN (?)", activity.id])
+ if period.present?
+ conditions.add(["tyear = ? AND tmonth = ?", period.year, period.month])
+ end
+ all_issues_total += issue.time_entries.all(:conditions => conditions.conditions).sum(&:cost)
all_issues_total
end
end
# Total hours spent for a given activity
- def hours_spent_for_activity(activity)
+ def hours_spent_for_activity(activity, options={})
issue_ids = issues.collect(&:id)
TimeEntry.sum(:hours,
:conditions => ["#{TimeEntry.table_name}.issue_id IN (?) AND activity_id IN (?)", issue_ids, activity.id])
end
# Total budget ($) for a given activity
- def budget_for_activity(activity)
- labor = labor_budgets.sum(:budget,
- :conditions => ["#{LaborBudget.table_name}.time_entry_activity_id IN (?)", activity.id])
- overhead = overhead_budgets.sum(:budget,
- :conditions => ["#{OverheadBudget.table_name}.time_entry_activity_id IN (?)", activity.id])
-
+ def budget_for_activity(activity, options={})
+ period = options[:period] || nil
+ labor_conditions = ARCondition.new(["#{LaborBudget.table_name}.time_entry_activity_id IN (?)", activity.id])
+ overhead_conditions = ARCondition.new(["#{OverheadBudget.table_name}.time_entry_activity_id IN (?)", activity.id])
+ if period.present?
+ labor_conditions.add(["#{LaborBudget.table_name}.year = ?", period.year])
+ labor_conditions.add(["#{LaborBudget.table_name}.month = ?", period.month])
+ overhead_conditions.add(["#{OverheadBudget.table_name}.year = ?", period.year])
+ overhead_conditions.add(["#{OverheadBudget.table_name}.month = ?", period.month])
+ end
+
+ labor = labor_budgets.sum(:budget, :conditions => labor_conditions.conditions)
+ overhead = overhead_budgets.sum(:budget, :conditions => overhead_conditions.conditions)
labor.to_f + overhead.to_f
end
# Total budget (hours) a given activity
- def hours_budget_for_activity(activity)
+ def hours_budget_for_activity(activity, options={})
labor = labor_budgets.sum(:hours,
:conditions => ["#{LaborBudget.table_name}.time_entry_activity_id IN (?)", activity.id])
overhead = overhead_budgets.sum(:hours,
diff --git a/app/views/deliverables/_finances.html.erb b/app/views/deliverables/_finances.html.erb
index da9c08d..6c8d09b 100644
--- a/app/views/deliverables/_finances.html.erb
+++ b/app/views/deliverables/_finances.html.erb
@@ -37,17 +37,17 @@
<%= h(activity.name) %>
|
-
- <%= number_to_currency(deliverable.spent_for_activity(activity), :precision => Deliverable::ViewPrecision) %>
+ |
+ <%= number_to_currency(deliverable.spent_for_activity(activity, :period => period), :precision => Deliverable::ViewPrecision) %>
|
- <%= number_to_currency(deliverable.budget_for_activity(activity), :precision => Deliverable::ViewPrecision) %>
+ <%= number_to_currency(deliverable.budget_for_activity(activity, :period => period), :precision => Deliverable::ViewPrecision) %>
|
-
- <%= number_with_precision(deliverable.hours_spent_for_activity(activity), :precision => Deliverable::ViewPrecision) %>
+ |
+ <%= number_with_precision(deliverable.hours_spent_for_activity(activity, :period => period), :precision => Deliverable::ViewPrecision) %>
|
- <%= number_with_precision(deliverable.hours_budget_for_activity(activity), :precision => Deliverable::ViewPrecision) %>
+ <%= number_with_precision(deliverable.hours_budget_for_activity(activity, :period => period), :precision => Deliverable::ViewPrecision) %>
|
<% end %>
@@ -87,17 +87,17 @@
<%= h(activity.name) %>
|
-
- <%= number_to_currency(deliverable.spent_for_activity(activity), :precision => Deliverable::ViewPrecision) %>
+ |
+ <%= number_to_currency(deliverable.spent_for_activity(activity, :period => period), :precision => Deliverable::ViewPrecision) %>
|
- <%= number_to_currency(deliverable.budget_for_activity(activity), :precision => Deliverable::ViewPrecision) %>
+ <%= number_to_currency(deliverable.budget_for_activity(activity, :period => period), :precision => Deliverable::ViewPrecision) %>
|
-
- <%= number_with_precision(deliverable.hours_spent_for_activity(activity), :precision => Deliverable::ViewPrecision) %>
+ |
+ <%= number_with_precision(deliverable.hours_spent_for_activity(activity, :period => period), :precision => Deliverable::ViewPrecision) %>
|
- <%= number_with_precision(deliverable.hours_budget_for_activity(activity), :precision => Deliverable::ViewPrecision) %>
+ <%= number_with_precision(deliverable.hours_budget_for_activity(activity, :period => period), :precision => Deliverable::ViewPrecision) %>
|
<% end %>
diff --git a/test/integration/deliverable_finances_test.rb b/test/integration/deliverable_finances_test.rb
index f6db682..52444aa 100644
--- a/test/integration/deliverable_finances_test.rb
+++ b/test/integration/deliverable_finances_test.rb
@@ -205,4 +205,92 @@ class DeliverableFinancesShowTest < ActionController::IntegrationTest
end
end
end
+
+ context "for a request for a different period" do
+ setup do
+ @period = "2010-02"
+ visit "/projects/#{@project.id}/contracts/#{@contract.id}/deliverables/#{@deliverable1.id}/finances?period=#{@period}"
+
+ assert_response :success
+
+ # All work done in setup() is past this period, only these items should show up.
+ Rate.generate!(:project => @deliverable1.project,
+ :user => @manager,
+ :date_in_effect => Date.new(2010, 2, 15),
+ :amount => 45)
+ # 2 hours of $45 billable work
+ create_issue_with_time_for_deliverable(@deliverable1, {
+ :activity => @billable_activity,
+ :user => @manager,
+ :hours => 2,
+ :spent_on => Date.new(2010, 2,15),
+ :skip_rate => true,
+ :issue_category => @category_on_billable
+ })
+ # 1 hour of $45 billable work with no category
+ create_issue_with_time_for_deliverable(@deliverable1, {
+ :activity => @billable_activity,
+ :user => @manager,
+ :hours => 1,
+ :spent_on => Date.new(2010, 2,15),
+ :skip_rate => true,
+ :issue_category => nil
+ })
+ # 3 hours of $45 nonbillable work
+ create_issue_with_time_for_deliverable(@deliverable1, {
+ :activity => @non_billable_activity,
+ :user => @manager,
+ :hours => 3,
+ :spent_on => Date.new(2010, 2, 15),
+ :skip_rate => true,
+ :issue_category => @category_on_non_billable
+ })
+
+ end
+
+ should "calculate activity values based on the period only" do
+ # Labor
+ assert_select "table#deliverable-labor-activities" do
+ assert_select "tr.labor" do
+ assert_select "td", :text => /#{@billable_activity.name}/
+ assert_select "td.spent-amount", :text => /\$135/ # 3 * $45
+ assert_select "td.total-amount", :text => /\$100/ # 1 month
+ assert_select "td.spent-hours", :text => /3/
+ assert_select "td.total-deliverable-hours", :text => /10/ # 1 month
+ end
+
+ assert_select "tr.summary-row.labor" do
+ assert_select "td", :text => /Totals/
+ assert_select "td.spent-amount", :text => /\$135/
+ assert_select "td.total-amount", :text => /\$100/
+ assert_select "td.spent-hours", :text => /3/
+ assert_select "td.total-deliverable-hours", :text => /10/
+ end
+
+ end
+
+ # Overhead
+ assert_select "table#deliverable-overhead-activities" do
+ assert_select "tr.overhead" do
+ assert_select "td", :text => /#{@non_billable_activity.name}/
+ assert_select "td.spent-amount", :text => /\$135/
+ assert_select "td.total-amount", :text => /\$200/
+ assert_select "td.spent-hours", :text => /3/
+ assert_select "td.total-deliverable-hours", :text => /10/ # 3 month retainer * 10
+ end
+
+ assert_select "tr.summary-row.overhead" do
+ assert_select "td", :text => /Totals/
+ assert_select "td.spent-amount", :text => /\$135/
+ assert_select "td.total-amount", :text => /\$200/
+ assert_select "td.spent-hours", :text => /5/
+ assert_select "td.total-deliverable-hours", :text => /10/
+ end
+ end
+
+ end
+
+ should "calculate user values based on the period only"
+ should "calculate issue category values based on the period only"
+ end
end
diff --git a/test/test_helper.rb b/test/test_helper.rb
index 5373422..c0ae688 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -131,18 +131,20 @@ class ActiveSupport::TestCase
amount = options[:amount] || 100
hours = options[:hours] || 2
issue_category = options[:issue_category]
+ skip_rate = options[:skip_rate] || false
+ spent_on = options[:spent_on] || Date.today
issue = Issue.generate_for_project!(project, :category_id => issue_category.try(:id))
time_entry = TimeEntry.generate!(:issue => issue,
:project => project,
:activity => activity,
- :spent_on => Date.today,
+ :spent_on => spent_on,
:hours => hours,
:user => user)
rate = Rate.generate!(:project => project,
:user => user,
:date_in_effect => Date.yesterday,
- :amount => amount)
+ :amount => amount) unless skip_rate
deliverable.issues << issue
issue
end
diff --git a/test/unit/deliverable_test.rb b/test/unit/deliverable_test.rb
index 75ea378..fe868c3 100644
--- a/test/unit/deliverable_test.rb
+++ b/test/unit/deliverable_test.rb
@@ -141,6 +141,31 @@ class DeliverableTest < ActiveSupport::TestCase
assert_equal 500.0, @deliverable.spent_for_activity(@billable_activity).to_f
end
+
+ should "return the total amount spent for an activity during the period" do
+ configure_overhead_plugin
+ create_contract_and_deliverable
+ Rate.generate!(:project => @deliverable.project,
+ :user => @manager,
+ :date_in_effect => Date.new(2010, 2, 15),
+ :amount => 45)
+ create_issue_with_time_for_deliverable(@deliverable, {
+ :activity => @billable_activity,
+ :user => @manager,
+ :hours => 5,
+ :amount => 100
+ })
+ create_issue_with_time_for_deliverable(@deliverable, {
+ :activity => @billable_activity,
+ :user => @manager,
+ :hours => 2,
+ :spent_on => Date.new(2010, 2,15),
+ :skip_rate => true,
+ :issue_category => @category_on_billable
+ })
+
+ assert_equal 90.0, @deliverable.spent_for_activity(@billable_activity, :period => Date.new(2010,2,1)).to_f
+ end
end
context "#budget_for_activity" do
@@ -153,7 +178,17 @@ class DeliverableTest < ActiveSupport::TestCase
assert_equal 600.0, @deliverable.budget_for_activity(@billable_activity).to_f # 200 * 3 months (retainer)
end
-
+
+ should "return the total amount budgeted for an activity during the period" do
+ configure_overhead_plugin
+ create_contract_and_deliverable
+ @deliverable.labor_budgets << LaborBudget.spawn(:budget => 100, :hours => 10, :time_entry_activity => @billable_activity)
+ @deliverable.labor_budgets << LaborBudget.spawn(:budget => 100, :hours => 10, :time_entry_activity => @billable_activity)
+ @deliverable.save!
+
+ assert_equal 200.0, @deliverable.budget_for_activity(@billable_activity, :period => Date.new(2010,2,1)).to_f # 200 * 1 months (retainer)
+ end
+
end
context "#hours_spent_for_activity" do
@@ -170,7 +205,8 @@ class DeliverableTest < ActiveSupport::TestCase
assert_equal 5.0, @deliverable.hours_spent_for_activity(@billable_activity).to_f
end
-
+
+ should "return the total hours spent for an activity during the period"
end
context "#hours_budget_for_activity" do
@@ -183,7 +219,8 @@ class DeliverableTest < ActiveSupport::TestCase
assert_equal 60.0, @deliverable.hours_budget_for_activity(@billable_activity).to_f # 20 * 3 months (retainer)
end
-
+
+ should "return the total hours budgeted for an activity during the period" do
end
context "#users_with_billable_time" do