[#4420] Hook up Retainer's total_spent and profit_left for periods.
This commit is contained in:
@@ -16,7 +16,7 @@ class FixedDeliverable < Deliverable
|
||||
end
|
||||
|
||||
# Fixed deliverables are always 100% spent
|
||||
def total_spent
|
||||
def total_spent(date=nil)
|
||||
total
|
||||
end
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ class HourlyDeliverable < Deliverable
|
||||
|
||||
# Total amount to be billed on the deliverable, using the total time logged
|
||||
# and the contract rate
|
||||
def total_spent
|
||||
def total_spent(date=nil)
|
||||
return 0 if contract.nil?
|
||||
return 0 if contract.billable_rate.blank?
|
||||
return 0 unless self.issues.count > 0
|
||||
@@ -56,7 +56,7 @@ class HourlyDeliverable < Deliverable
|
||||
|
||||
# The amount of money remaining after expenses have been taken out
|
||||
# Profit left = Total - Labor spent - Overhead spent
|
||||
def profit_left
|
||||
total_spent - labor_budget_spent - overhead_spent
|
||||
def profit_left(date=nil)
|
||||
total_spent(date) - labor_budget_spent(date) - overhead_spent(date)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -111,6 +111,40 @@ class RetainerDeliverable < HourlyDeliverable
|
||||
end
|
||||
end
|
||||
|
||||
def total_spent(date=nil)
|
||||
if date
|
||||
if within_date_range?(date)
|
||||
# TODO: duplicated on HourlyDeliverable#total_spent
|
||||
return 0 if contract.nil?
|
||||
return 0 if contract.billable_rate.blank?
|
||||
return 0 unless self.issues.count > 0
|
||||
|
||||
issue_ids = self.issues.collect(&:id)
|
||||
if issue_ids.present?
|
||||
time_logs = TimeEntry.all(:conditions => ["#{Issue.table_name}.id IN (:issue_ids) AND tyear = (:year) AND tmonth = (:month)",
|
||||
{:issue_ids => issue_ids,
|
||||
:year => date.year,
|
||||
:month => date.month}
|
||||
],
|
||||
:include => :issue)
|
||||
end
|
||||
time_logs ||= []
|
||||
hours = time_logs.inject(0) {|total, time_entry|
|
||||
total += time_entry.hours if time_entry.billable?
|
||||
total
|
||||
}
|
||||
|
||||
return hours * contract.billable_rate
|
||||
|
||||
else
|
||||
0 # outside of range
|
||||
end
|
||||
else
|
||||
super
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# TODO: stolen directly from redmine_overhead but with a block option
|
||||
def labor_budget_spent_with_filter(&block)
|
||||
return 0.0 unless self.issues.size > 0
|
||||
|
||||
@@ -271,7 +271,71 @@ class RetainerDeliverableTest < ActiveSupport::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
# context "#profit_left"
|
||||
# (Labor used * contract rate) - (labor used * time rate) - (overhead used * time rate)
|
||||
context "#profit_left" do
|
||||
setup do
|
||||
@project = Project.generate!
|
||||
@contract = Contract.generate!(:billable_rate => 200, :project => @project)
|
||||
@deliverable = RetainerDeliverable.generate!(:start_date => '2010-01-01', :end_date => '2010-03-31', :contract => @contract)
|
||||
@deliverable.labor_budgets << LaborBudget.spawn(:budget => 100, :hours => 10)
|
||||
@deliverable.overhead_budgets << OverheadBudget.spawn(:budget => 100, :hours => 10)
|
||||
@deliverable.save!
|
||||
|
||||
@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
|
||||
|
||||
|
||||
end
|
||||
|
||||
context "with a empty period" do
|
||||
should "use all periods" do
|
||||
assert_equal (10 * 200) - (10 * 100) - (20 * 100), @deliverable.profit_left(nil)
|
||||
end
|
||||
end
|
||||
|
||||
context "with a period out of the retainer range" do
|
||||
should "filter the records periods" do
|
||||
assert_equal 0, @deliverable.profit_left(Date.new(2011,1,1))
|
||||
end
|
||||
end
|
||||
|
||||
context "with an invalid period" do
|
||||
should "return 0" do
|
||||
assert_equal 0, @deliverable.profit_left('1')
|
||||
end
|
||||
end
|
||||
|
||||
context "with a period in the retainer range" do
|
||||
should "filter the records" do
|
||||
assert_equal (0 * 200) - (0 * 100) - (20 * 100), @deliverable.profit_left(Date.new(2010,2,1))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
context "#profit_budget" do
|
||||
setup do
|
||||
@@ -311,8 +375,71 @@ class RetainerDeliverableTest < ActiveSupport::TestCase
|
||||
|
||||
end
|
||||
|
||||
# context "#total_spent"
|
||||
|
||||
context "#total_spent" do
|
||||
setup do
|
||||
@project = Project.generate!
|
||||
@contract = Contract.generate!(:billable_rate => 200, :project => @project)
|
||||
@deliverable = RetainerDeliverable.generate!(:start_date => '2010-01-01', :end_date => '2010-03-31', :contract => @contract)
|
||||
@deliverable.labor_budgets << LaborBudget.spawn(:budget => 100, :hours => 10)
|
||||
@deliverable.overhead_budgets << OverheadBudget.spawn(:budget => 100, :hours => 10)
|
||||
@deliverable.save!
|
||||
|
||||
@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 => @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
|
||||
|
||||
|
||||
end
|
||||
|
||||
context "with a empty period" do
|
||||
should "use all periods" do
|
||||
# Labor used * contract rate
|
||||
assert_equal (10+20) * 200, @deliverable.total_spent(nil)
|
||||
end
|
||||
end
|
||||
|
||||
context "with a period out of the retainer range" do
|
||||
should "filter the records periods" do
|
||||
assert_equal 0, @deliverable.total_spent(Date.new(2011,1,1))
|
||||
end
|
||||
end
|
||||
|
||||
context "with an invalid period" do
|
||||
should "return 0" do
|
||||
assert_equal 0, @deliverable.total_spent('1')
|
||||
end
|
||||
end
|
||||
|
||||
context "with a period in the retainer range" do
|
||||
should "filter the records" do
|
||||
assert_equal 20 * 200, @deliverable.total_spent(Date.new(2010,2,1))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "#total" do
|
||||
setup do
|
||||
@contract = Contract.generate!(:billable_rate => 100)
|
||||
|
||||
Reference in New Issue
Block a user