From 7f7e5b30421cfb88ccd3c3aa15b3ceeeaecb8985 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 9 Sep 2010 15:57:58 -0700 Subject: [PATCH 01/16] [#4477] Added model and migration for FixedBudget. --- app/models/deliverable.rb | 1 + app/models/fixed_budget.rb | 10 ++++++++++ db/migrate/015_create_fixed_budgets.rb | 19 +++++++++++++++++++ test/unit/deliverable_test.rb | 1 + test/unit/fixed_budget_test.rb | 6 ++++++ 5 files changed, 37 insertions(+) create mode 100644 app/models/fixed_budget.rb create mode 100644 db/migrate/015_create_fixed_budgets.rb create mode 100644 test/unit/fixed_budget_test.rb diff --git a/app/models/deliverable.rb b/app/models/deliverable.rb index 3517409..b83eb54 100644 --- a/app/models/deliverable.rb +++ b/app/models/deliverable.rb @@ -8,6 +8,7 @@ class Deliverable < ActiveRecord::Base belongs_to :manager, :class_name => 'User', :foreign_key => 'manager_id' has_many :labor_budgets has_many :overhead_budgets + has_many :fixed_budgets has_many :issues accepts_nested_attributes_for :labor_budgets diff --git a/app/models/fixed_budget.rb b/app/models/fixed_budget.rb new file mode 100644 index 0000000..783e560 --- /dev/null +++ b/app/models/fixed_budget.rb @@ -0,0 +1,10 @@ +class FixedBudget < ActiveRecord::Base + unloadable + + # Associations + belongs_to :deliverable + + # Validations + + # Accessors +end diff --git a/db/migrate/015_create_fixed_budgets.rb b/db/migrate/015_create_fixed_budgets.rb new file mode 100644 index 0000000..631d4f7 --- /dev/null +++ b/db/migrate/015_create_fixed_budgets.rb @@ -0,0 +1,19 @@ +class CreateFixedBudgets < ActiveRecord::Migration + def self.up + create_table :fixed_budgets do |t| + t.string :title + t.decimal :budget, :precision => 15, :scale => 4 + t.string :markup + t.text :description + t.references :deliverable + + t.timestamps + end + + add_index :fixed_budgets, :deliverable_id + end + + def self.down + drop_table :fixed_budgets + end +end diff --git a/test/unit/deliverable_test.rb b/test/unit/deliverable_test.rb index 6691318..694adc0 100644 --- a/test/unit/deliverable_test.rb +++ b/test/unit/deliverable_test.rb @@ -5,6 +5,7 @@ class DeliverableTest < ActiveSupport::TestCase should_belong_to :manager should_have_many :labor_budgets should_have_many :overhead_budgets + should_have_many :fixed_budgets should_have_many :issues should_validate_presence_of :title diff --git a/test/unit/fixed_budget_test.rb b/test/unit/fixed_budget_test.rb new file mode 100644 index 0000000..09c18d1 --- /dev/null +++ b/test/unit/fixed_budget_test.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class FixedBudgetTest < ActiveSupport::TestCase + should_belong_to :deliverable + +end From 07da5d98d8e0c6bce58930dc79affe17ab944aaf Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 9 Sep 2010 16:12:48 -0700 Subject: [PATCH 02/16] [#4477] Added the FixedBudget markup calculations. --- app/models/fixed_budget.rb | 23 +++++++++++++++++++++++ test/unit/fixed_budget_test.rb | 27 +++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/app/models/fixed_budget.rb b/app/models/fixed_budget.rb index 783e560..ff04099 100644 --- a/app/models/fixed_budget.rb +++ b/app/models/fixed_budget.rb @@ -7,4 +7,27 @@ class FixedBudget < ActiveRecord::Base # Validations # Accessors + def markup_value + return 0 if budget.blank? || markup.blank? + + case + when percent_markup? + percent = markup.gsub('%','').to_f + return budget.to_f * (percent / 100) + when straight_markup? + markup.gsub('$','').gsub(',','').to_f + else + 0 # Invalid markup + end + + end + + def percent_markup? + markup && markup.match(/%/) + end + + def straight_markup? + markup && markup.match(/\$/) + end + end diff --git a/test/unit/fixed_budget_test.rb b/test/unit/fixed_budget_test.rb index 09c18d1..2ea7def 100644 --- a/test/unit/fixed_budget_test.rb +++ b/test/unit/fixed_budget_test.rb @@ -3,4 +3,31 @@ require File.dirname(__FILE__) + '/../test_helper' class FixedBudgetTest < ActiveSupport::TestCase should_belong_to :deliverable + context "#markup_value" do + setup do + @fixed_budget = FixedBudget.new(:budget => 1000) + end + + context "with no markup" do + should "be 0" do + assert_equal nil, @fixed_budget.markup + assert_equal 0, @fixed_budget.markup_value + end + end + + context "with a % markup" do + should "equal the budget times the %" do + @fixed_budget.markup = '50%' + assert_equal 500, @fixed_budget.markup_value + end + end + + context "with a $ markup" do + should "equal the $ markup (straight markup)" do + @fixed_budget.markup = '$4,000.57' + assert_equal 4000.57, @fixed_budget.markup_value + end + end + + end end From feee5e8b43f7851e6e5bf09f30f2ba7bcd002ede Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 9 Sep 2010 17:06:35 -0700 Subject: [PATCH 03/16] [#4477] Added FixedBudgets to the Deliverable finance form. --- app/helpers/contracts_helper.rb | 1 + app/models/deliverable.rb | 1 + app/models/fixed_budget.rb | 8 ++ app/models/retainer_deliverable.rb | 6 ++ app/views/deliverables/_finance_form.html.erb | 31 ++++++++ app/views/deliverables/_form.html.erb | 6 +- config/locales/en.yml | 3 +- ...016_add_year_and_month_to_fixed_budgets.rb | 14 ++++ test/integration/deliverables_new_test.rb | 74 ++++++++++++------- 9 files changed, 115 insertions(+), 29 deletions(-) create mode 100644 db/migrate/016_add_year_and_month_to_fixed_budgets.rb diff --git a/app/helpers/contracts_helper.rb b/app/helpers/contracts_helper.rb index 0266bd0..ef553e2 100644 --- a/app/helpers/contracts_helper.rb +++ b/app/helpers/contracts_helper.rb @@ -3,6 +3,7 @@ module ContractsHelper returning(deliverable) do |d| d.labor_budgets.build if d.labor_budgets.empty? d.overhead_budgets.build if d.overhead_budgets.empty? + d.fixed_budgets.build if d.fixed_budgets.empty? end end diff --git a/app/models/deliverable.rb b/app/models/deliverable.rb index b83eb54..9f2f677 100644 --- a/app/models/deliverable.rb +++ b/app/models/deliverable.rb @@ -13,6 +13,7 @@ class Deliverable < ActiveRecord::Base accepts_nested_attributes_for :labor_budgets accepts_nested_attributes_for :overhead_budgets + accepts_nested_attributes_for :fixed_budgets # Validations validates_presence_of :title diff --git a/app/models/fixed_budget.rb b/app/models/fixed_budget.rb index ff04099..9ea971c 100644 --- a/app/models/fixed_budget.rb +++ b/app/models/fixed_budget.rb @@ -7,6 +7,14 @@ class FixedBudget < ActiveRecord::Base # Validations # Accessors + def budget=(v) + if v.is_a? String + write_attribute(:budget, v.gsub(/[$ ,]/, '')) + else + write_attribute(:budget, v) + end + end + def markup_value return 0 if budget.blank? || markup.blank? diff --git a/app/models/retainer_deliverable.rb b/app/models/retainer_deliverable.rb index 0a675d6..d8f07ad 100644 --- a/app/models/retainer_deliverable.rb +++ b/app/models/retainer_deliverable.rb @@ -83,6 +83,12 @@ class RetainerDeliverable < HourlyDeliverable budgets end + def fixed_budgets_for_date(date) + budgets = fixed_budgets.all(:conditions => {:year => date.year, :month => date.month}) + budgets = [fixed_budgets.build(:year => date.year, :month => date.month)] if budgets.empty? + budgets + end + def labor_budget_total(date=nil) case scope_date_status(date) when :in diff --git a/app/views/deliverables/_finance_form.html.erb b/app/views/deliverables/_finance_form.html.erb index b77a973..6c3d44d 100644 --- a/app/views/deliverables/_finance_form.html.erb +++ b/app/views/deliverables/_finance_form.html.erb @@ -62,6 +62,37 @@ +
  • +
    + + + <% form.fields_for :fixed_budgets, fixed_budgets do |fixed_budget| %> + + <%= fixed_budget.text_field(:title) %> + +

    + <%= fixed_budget.label(:budget, l(:field_budget), :style => 'display: none;')%> <%# Hidden label :| %> + <%= l(:text_dollar_sign) %> +

    + <%= fixed_budget.text_field(:budget) %> + +

    + <%= fixed_budget.label(:markup, l(:field_markup), :style => 'display: none;')%> <%# Hidden label :| %> + <%= l(:field_discount_hint) %> +

    + <%= fixed_budget.text_field(:markup) %> + + + <%= fixed_budget.text_area(:description, :class => 'wiki-edit', :rows => '5', :id => "fixed-description#{fixed_budget.object.object_id}") %> + <%= wikitoolbar_for "fixed-description#{fixed_budget.object.object_id}" %> + +

    Todo: Add button (Release 3)

    + <% end %> +
    + + +
  • + <%= form.input :total, :input_html => {:size => 10}, :wrapper_html => {:class => 'deliverable_total_input'}, :hint => l(:text_dollar_sign) %> <% end %> diff --git a/app/views/deliverables/_form.html.erb b/app/views/deliverables/_form.html.erb index 8d0f7ef..ac810c3 100644 --- a/app/views/deliverables/_form.html.erb +++ b/app/views/deliverables/_form.html.erb @@ -3,7 +3,7 @@ <%= javascript_tag("var i18nChangedPeriodMessage = '#{l(:text_changed_period_message)}'") %>
    -<% form.inputs :name => l(:text_deliverable_details_legend) do %> +<% form.inputs :name => l(:text_deliverable_details_legend), :id => 'deliverable-details' do %> <%# Used by jquery to check if this is a new or existing record %> <%= hidden_field_tag('deliverable_id', h(resource.id), :id => 'deliverable_stored_id') %> <%= form.input :title, :required => true %> @@ -40,13 +40,13 @@ <% if resource.retainer? && resource.respond_to?(:months) %> <% if resource.months.present? %> <% resource.months.each do |month| %> -<%= render :partial => 'finance_form', :locals => {:form => form, :labor_budgets => resource.labor_budgets_for_date(month), :overhead_budgets => resource.overhead_budgets_for_date(month), :label => l(:text_deliverable_finances_date, :date => month.strftime("%B, %Y")), :fieldset_class => 'date-' + month.strftime('%Y-%m') } %> +<%= render :partial => 'finance_form', :locals => {:form => form, :labor_budgets => resource.labor_budgets_for_date(month), :overhead_budgets => resource.overhead_budgets_for_date(month), :fixed_budgets => resource.fixed_budgets_for_date(month), :label => l(:text_deliverable_finances_date, :date => month.strftime("%B, %Y")), :fieldset_class => 'date-' + month.strftime('%Y-%m') } %> <% end %> <% else %> <%= content_tag(:p, l(:text_missing_period), :class => 'nodata') %> <% end %> <% else %> -<%= render :partial => 'finance_form', :locals => {:form => form, :labor_budgets => resource.labor_budgets, :overhead_budgets => resource.overhead_budgets, :label => l(:text_deliverable_finances), :fieldset_class => '' } %> +<%= render :partial => 'finance_form', :locals => {:form => form, :labor_budgets => resource.labor_budgets, :overhead_budgets => resource.overhead_budgets, :fixed_budgets => resource.fixed_budgets, :label => l(:text_deliverable_finances), :fieldset_class => '' } %> <% end %>
    diff --git a/config/locales/en.yml b/config/locales/en.yml index e12914d..64c8cad 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -70,4 +70,5 @@ en: text_flash_deliverable_created: "Deliverable: {{name}} was successfully created." text_flash_deliverable_updated: "Deliverable: {{name}} was successfully updated." text_flash_deliverable_destroyed: "Deliverable: {{name}} was successfully destroyed." - + field_budget: Budget + field_markup: Markup diff --git a/db/migrate/016_add_year_and_month_to_fixed_budgets.rb b/db/migrate/016_add_year_and_month_to_fixed_budgets.rb new file mode 100644 index 0000000..7c71ea1 --- /dev/null +++ b/db/migrate/016_add_year_and_month_to_fixed_budgets.rb @@ -0,0 +1,14 @@ +class AddYearAndMonthToFixedBudgets < ActiveRecord::Migration + def self.up + add_column :fixed_budgets, :year, :integer + add_index :fixed_budgets, :year + + add_column :fixed_budgets, :month, :integer + add_index :fixed_budgets, :month + end + + def self.down + remove_column :fixed_budgets, :year + remove_column :fixed_budgets, :month + end +end diff --git a/test/integration/deliverables_new_test.rb b/test/integration/deliverables_new_test.rb index 0c2ef2a..a211f6d 100644 --- a/test/integration/deliverables_new_test.rb +++ b/test/integration/deliverables_new_test.rb @@ -50,12 +50,15 @@ class DeliverablesNewTest < ActionController::IntegrationTest click_link 'Add New' assert_response :success - fill_in "Title", :with => 'A New Deliverable' - select "Fixed", :from => "Type" - select @manager.name, :from => "Manager" - fill_in "Start", :with => '2010-01-01' - fill_in "End Date", :with => '2010-12-31' - fill_in "Notes", :with => 'Some notes on the deliverable' + within("#deliverable-details") do + fill_in "Title", :with => 'A New Deliverable' + select "Fixed", :from => "Type" + select @manager.name, :from => "Manager" + fill_in "Start", :with => '2010-01-01' + fill_in "End Date", :with => '2010-12-31' + fill_in "Notes", :with => 'Some notes on the deliverable' + end + fill_in "Total", :with => '1,000.00' # TODO: webrat can't trigger DOM events so it can't appear # assert js("jQuery('#deliverable_total').is(':visible')"), "Total is hidden when it should be visible" @@ -84,12 +87,14 @@ class DeliverablesNewTest < ActionController::IntegrationTest click_link 'Add New' assert_response :success - fill_in "Title", :with => 'A New Deliverable' - select "Hourly", :from => "Type" - select @manager.name, :from => "Manager" - fill_in "Start", :with => '2010-01-01' - fill_in "End Date", :with => '2010-12-31' - fill_in "Notes", :with => 'Some notes on the deliverable' + within("#deliverable-details") do + fill_in "Title", :with => 'A New Deliverable' + select "Hourly", :from => "Type" + select @manager.name, :from => "Manager" + fill_in "Start", :with => '2010-01-01' + fill_in "End Date", :with => '2010-12-31' + fill_in "Notes", :with => 'Some notes on the deliverable' + end fill_in "Total", :with => '1,000.00' # # Hide and clear the total @@ -120,13 +125,15 @@ class DeliverablesNewTest < ActionController::IntegrationTest click_link 'Add New' assert_response :success - fill_in "Title", :with => 'A New Deliverable' - select "Retainer", :from => "Type" - select @manager.name, :from => "Manager" - fill_in "Start", :with => '2010-01-01' - fill_in "End Date", :with => '2010-12-31' - fill_in "Notes", :with => 'Some notes on the deliverable' - + within("#deliverable-details") do + fill_in "Title", :with => 'A New Deliverable' + select "Retainer", :from => "Type" + select @manager.name, :from => "Manager" + fill_in "Start", :with => '2010-01-01' + fill_in "End Date", :with => '2010-12-31' + fill_in "Notes", :with => 'Some notes on the deliverable' + end + within("#deliverable-labor") do fill_in "hrs", :with => '20' fill_in "$", :with => '$2,000' @@ -193,12 +200,14 @@ class DeliverablesNewTest < ActionController::IntegrationTest click_link 'Add New' assert_response :success - fill_in "Title", :with => 'A New Deliverable' - select "Hourly", :from => "Type" - select @manager.name, :from => "Manager" - fill_in "Start", :with => '2010-01-01' - fill_in "End Date", :with => '2010-12-31' - fill_in "Notes", :with => 'Some notes on the deliverable' + within("#deliverable-details") do + fill_in "Title", :with => 'A New Deliverable' + select "Hourly", :from => "Type" + select @manager.name, :from => "Manager" + fill_in "Start", :with => '2010-01-01' + fill_in "End Date", :with => '2010-12-31' + fill_in "Notes", :with => 'Some notes on the deliverable' + end within("#deliverable-labor") do fill_in "hrs", :with => '20' @@ -210,6 +219,13 @@ class DeliverablesNewTest < ActionController::IntegrationTest fill_in "$", :with => '$1,000' end + within("#deliverable-fixed") do + fill_in "title", :with => 'Flight to NYC' + fill_in "budget", :with => '$600' + fill_in "markup", :with => '50%' + fill_in "description", :with => 'Need to fly to NYC for the week' + end + click_button "Save" assert_response :success @@ -226,6 +242,14 @@ class DeliverablesNewTest < ActionController::IntegrationTest @overhead_budget = @deliverable.overhead_budgets.first assert_equal 10, @overhead_budget.hours assert_equal 1000.0, @overhead_budget.budget + + assert_equal 1, @deliverable.fixed_budgets.count + @fixed_budget = @deliverable.fixed_budgets.first + assert_equal "Flight to NYC", @fixed_budget.title + assert_equal 600, @fixed_budget.budget + assert_equal "50%", @fixed_budget.markup + assert_equal 300, @fixed_budget.markup_value # 600 * 50% + end end From edc8db7fe24187fbb876e06da7201aeae60bd051 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 9 Sep 2010 17:27:32 -0700 Subject: [PATCH 04/16] [#4477] Hook FixedBudgets into Retainer's periods. --- app/models/retainer_deliverable.rb | 35 +++++++- app/views/deliverables/_finance_form.html.erb | 3 + test/integration/deliverables_edit_test.rb | 81 ++++++++++++++++--- 3 files changed, 106 insertions(+), 13 deletions(-) diff --git a/app/models/retainer_deliverable.rb b/app/models/retainer_deliverable.rb index d8f07ad..25fa354 100644 --- a/app/models/retainer_deliverable.rb +++ b/app/models/retainer_deliverable.rb @@ -226,10 +226,16 @@ class RetainerDeliverable < HourlyDeliverable undated_overhead_budgets.each do |template_budget| overhead_budgets.create(template_budget.attributes.merge(:year => month.year, :month => month.month)) end + + undated_fixed_budgets = fixed_budgets.all(:conditions => ["#{FixedBudget.table_name}.year IS NULL AND #{FixedBudget.table_name}.month IS NULL"]) + undated_fixed_budgets.each do |template_budget| + fixed_budgets.create(template_budget.attributes.merge(:year => month.year, :month => month.month)) + end end # Destroy origional un-dated budgets labor_budgets.all(:conditions => ["#{LaborBudget.table_name}.year IS NULL AND #{LaborBudget.table_name}.month IS NULL"]).collect(&:destroy) overhead_budgets.all(:conditions => ["#{OverheadBudget.table_name}.year IS NULL AND #{OverheadBudget.table_name}.month IS NULL"]).collect(&:destroy) + fixed_budgets.all(:conditions => ["#{FixedBudget.table_name}.year IS NULL AND #{FixedBudget.table_name}.month IS NULL"]).collect(&:destroy) end def check_for_extended_period @@ -276,6 +282,17 @@ class RetainerDeliverable < HourlyDeliverable end end + fixed_budgets.all.each do |fixed_budget| + # Purge un-dated budgets, should not be saved at all + fixed_budget.destroy unless fixed_budget.year.present? + fixed_budget.destroy unless fixed_budget.month.present? + + # Purge budgets outside the new beginning/ending range + unless (beginning_date..ending_date).to_a.include?(Date.new(fixed_budget.year, fixed_budget.month, 1)) + fixed_budget.destroy + end + end + true end @@ -285,9 +302,10 @@ class RetainerDeliverable < HourlyDeliverable old_end_date = end_date_change[0] last_labor_budgets = labor_budgets.all(:conditions => {:year => old_end_date.year, :month => old_end_date.month}) last_overhead_budgets = overhead_budgets.all(:conditions => {:year => old_end_date.year, :month => old_end_date.month}) - + last_fixed_budgets = fixed_budgets.all(:conditions => {:year => old_end_date.year, :month => old_end_date.month}) + months_after_date(old_end_date.end_of_month.to_date).each do |new_period| - create_budgets_for_new_period(new_period, last_labor_budgets, last_overhead_budgets) + create_budgets_for_new_period(new_period, last_labor_budgets, last_overhead_budgets, last_fixed_budgets) end end @@ -297,14 +315,15 @@ class RetainerDeliverable < HourlyDeliverable old_start_date = start_date_change[0] first_labor_budgets = labor_budgets.all(:conditions => {:year => old_start_date.year, :month => old_start_date.month}) first_overhead_budgets = overhead_budgets.all(:conditions => {:year => old_start_date.year, :month => old_start_date.month}) + first_fixed_budgets = fixed_budgets.all(:conditions => {:year => old_start_date.year, :month => old_start_date.month}) months_before_date(old_start_date.beginning_of_month.to_date).each do |new_period| - create_budgets_for_new_period(new_period, first_labor_budgets, first_overhead_budgets) + create_budgets_for_new_period(new_period, first_labor_budgets, first_overhead_budgets, first_fixed_budgets) end end - def create_budgets_for_new_period(new_period, labor_budgets_to_copy, overhead_budgets_to_copy) + def create_budgets_for_new_period(new_period, labor_budgets_to_copy, overhead_budgets_to_copy, fixed_budgets_to_copy) labor_budgets_to_copy.each do |labor_budget_to_copy| create_new_labor_budget_based_on_existing_budget(labor_budget_to_copy, 'year' => new_period.year, 'month' => new_period.month) end @@ -312,6 +331,10 @@ class RetainerDeliverable < HourlyDeliverable overhead_budgets_to_copy.each do |overhead_budget_to_copy| create_new_overhead_budget_based_on_existing_budget(overhead_budget_to_copy, 'year' => new_period.year, 'month' => new_period.month) end + + fixed_budgets_to_copy.each do |fixed_budget_to_copy| + create_new_fixed_budget_based_on_existing_budget(fixed_budget_to_copy, 'year' => new_period.year, 'month' => new_period.month) + end end def create_new_labor_budget_based_on_existing_budget(existing_labor_budget, attributes={}) @@ -322,6 +345,10 @@ class RetainerDeliverable < HourlyDeliverable overhead_budgets.create(existing_overhead_budget.attributes.except('id').merge(attributes)) end + def create_new_fixed_budget_based_on_existing_budget(existing_fixed_budget, attributes={}) + fixed_budgets.create(existing_fixed_budget.attributes.except('id').merge(attributes)) + end + def scope_date_status(date) if date if within_date_range?(date) diff --git a/app/views/deliverables/_finance_form.html.erb b/app/views/deliverables/_finance_form.html.erb index 6c3d44d..0942953 100644 --- a/app/views/deliverables/_finance_form.html.erb +++ b/app/views/deliverables/_finance_form.html.erb @@ -67,6 +67,9 @@ <% form.fields_for :fixed_budgets, fixed_budgets do |fixed_budget| %> + <%= fixed_budget.hidden_field(:year) %> + <%= fixed_budget.hidden_field(:month) %> + <%= fixed_budget.text_field(:title) %> diff --git a/test/integration/deliverables_edit_test.rb b/test/integration/deliverables_edit_test.rb index c38cb74..b139622 100644 --- a/test/integration/deliverables_edit_test.rb +++ b/test/integration/deliverables_edit_test.rb @@ -27,10 +27,11 @@ class DeliverablesEditTest < ActionController::IntegrationTest assert_select "select#fixed_deliverable_type", :count => 0 # Not editable assert js("jQuery('#fixed_deliverable_total_input').is(':visible')"), "Total is hidden when it should be visible" - - fill_in "Title", :with => 'An updated title' - check "Feature Sign Off" - check "Warranty Sign Off" + within("#deliverable-details") do + fill_in "Title", :with => 'An updated title' + check "Feature Sign Off" + check "Warranty Sign Off" + end click_button "Save" assert_response :success @@ -56,9 +57,11 @@ class DeliverablesEditTest < ActionController::IntegrationTest assert_select "select#hourly_deliverable_type", :count => 0 # Not editable assert js("jQuery('#hourly_deliverable_total_input').is(':hidden')"), "Total is visible when it should be hidden" - fill_in "Title", :with => 'An updated title' - check "Feature Sign Off" - check "Warranty Sign Off" + within("#deliverable-details") do + fill_in "Title", :with => 'An updated title' + check "Feature Sign Off" + check "Warranty Sign Off" + end within("#deliverable-labor") do fill_in "hrs", :with => '20' @@ -95,6 +98,8 @@ class DeliverablesEditTest < ActionController::IntegrationTest @retainer_deliverable = RetainerDeliverable.spawn(:contract => @contract, :manager => @manager, :title => "Retainer") @retainer_deliverable.labor_budgets << @labor_budget = LaborBudget.spawn(:deliverable => @retainer_deliverable, :budget => 1000, :hours => 10) @retainer_deliverable.overhead_budgets << @overhead_budget = OverheadBudget.spawn(:deliverable => @retainer_deliverable, :budget => 1000, :hours => 10) + @retainer_deliverable.fixed_budgets << @fixed_budget = FixedBudget.spawn(:deliverable => @retainer_deliverable, :title => 'Printing supplies', :budget => 100, :markup => 0) + @retainer_deliverable.start_date = '2010-01-01' @retainer_deliverable.end_date = '2010-12-31' @retainer_deliverable.save! @@ -117,6 +122,13 @@ class DeliverablesEditTest < ActionController::IntegrationTest fill_in "hrs", :with => '100' fill_in "$", :with => '100' end + + within "#deliverable-fixed" do + fill_in "title", :with => 'Flight to NYC' + fill_in "budget", :with => '$600' + fill_in "markup", :with => '50%' + fill_in "description", :with => 'Need to fly to NYC for the week' + end end click_button "Save" @@ -157,6 +169,24 @@ class DeliverablesEditTest < ActionController::IntegrationTest end end + @fixed_budgets = @retainer_deliverable.reload.fixed_budgets + assert_equal 12, @fixed_budgets.length + @fixed_budgets.each do |fixed_budget| + if fixed_budget.year == 2010 && fixed_budget.month == 1 + + # Specific month's budget updated? + assert_equal 600, fixed_budget.budget + assert_equal '50%', fixed_budget.markup + assert_equal 300, fixed_budget.markup_value + + else + + assert_equal 100, fixed_budget.budget + assert_equal '0', fixed_budget.markup + + end + end + end should "allow extending a Retainer's start and end months" do @@ -175,6 +205,7 @@ class DeliverablesEditTest < ActionController::IntegrationTest @retainer_deliverable.labor_budgets << @labor_budget = LaborBudget.spawn(:deliverable => @retainer_deliverable, :budget => labor_budget_amount_2, :hours => labor_budget_hours_2) @retainer_deliverable.overhead_budgets << @overhead_budget = OverheadBudget.spawn(:deliverable => @retainer_deliverable, :budget => overhead_budget_amount_1, :hours => overhead_budget_hours_1) @retainer_deliverable.overhead_budgets << @overhead_budget = OverheadBudget.spawn(:deliverable => @retainer_deliverable, :budget => overhead_budget_amount_2, :hours => overhead_budget_hours_2) + @retainer_deliverable.fixed_budgets << @fixed_budget = FixedBudget.spawn(:deliverable => @retainer_deliverable, :title => 'Printing supplies', :budget => 100, :markup => 0) @retainer_deliverable.start_date = '2010-01-01' @retainer_deliverable.end_date = '2010-12-31' @retainer_deliverable.save! @@ -256,6 +287,17 @@ class DeliverablesEditTest < ActionController::IntegrationTest assert [overhead_budget_amount_1, overhead_budget_amount_2].include?(overhead_budget.budget), "Extended overhead budget dollars not matching template budget" end + @fixed_budgets = @retainer_deliverable.reload.fixed_budgets + assert_equal 36, @fixed_budgets.length # 36 months * 1 record + + @fixed_budgets_for_2009 = @fixed_budgets.select {|l| l.year == 2009 } + @fixed_budgets_for_2010 = @fixed_budgets.select {|l| l.year == 2010 } + @fixed_budgets_for_2011 = @fixed_budgets.select {|l| l.year == 2011 } + + assert_equal 12, @fixed_budgets_for_2009.length + assert_equal 12, @fixed_budgets_for_2010.length + assert_equal 12, @fixed_budgets_for_2011.length + end should "allow shrinking a Retainer's start and end months" do @@ -264,6 +306,7 @@ class DeliverablesEditTest < ActionController::IntegrationTest @retainer_deliverable.labor_budgets << @labor_budget = LaborBudget.spawn(:deliverable => @retainer_deliverable, :budget => 2000, :hours => 20) @retainer_deliverable.overhead_budgets << @overhead_budget = OverheadBudget.spawn(:deliverable => @retainer_deliverable, :budget => 1000, :hours => 10) @retainer_deliverable.overhead_budgets << @overhead_budget = OverheadBudget.spawn(:deliverable => @retainer_deliverable, :budget => 2000, :hours => 20) + @retainer_deliverable.fixed_budgets << @fixed_budget = FixedBudget.spawn(:deliverable => @retainer_deliverable, :title => 'Printing supplies', :budget => 100, :markup => 0) @retainer_deliverable.start_date = '2010-01-01' @retainer_deliverable.end_date = '2010-12-31' @retainer_deliverable.save! @@ -293,6 +336,9 @@ class DeliverablesEditTest < ActionController::IntegrationTest @overhead_budgets = @retainer_deliverable.reload.overhead_budgets assert_equal 12, @overhead_budgets.length # 6 months * 2 records + @fixed_budgets = @retainer_deliverable.reload.fixed_budgets + assert_equal 6, @fixed_budgets.length # 6 months * 1 records + end should "allow editing a Retainer's start and end months inside the current period" do @@ -346,7 +392,7 @@ class DeliverablesEditTest < ActionController::IntegrationTest assert_response :success assert_template 'deliverables/edit' - # Should show 6 inputs: + # Should show inputs: # * labor hidden year # * labor hidden month # * labor hours @@ -355,9 +401,15 @@ class DeliverablesEditTest < ActionController::IntegrationTest # * overhead hidden month # * overhead hours # * overhead amount + # * fixed hidden year + # * fixed hidden month + # * fixed title + # * fixed budget + # * fixed markup # * total (hidden) assert_select ".date-2010-01" do - assert_select "input", :count => 9 + assert_select "input", :count => 14 + assert_select "textarea.wiki-edit", :count => 1 # Fixed description end @@ -371,6 +423,14 @@ class DeliverablesEditTest < ActionController::IntegrationTest fill_in "hrs", :with => '100' fill_in "$", :with => '100' end + + within "#deliverable-fixed" do + fill_in "title", :with => 'Flight to NYC' + fill_in "budget", :with => '$600' + fill_in "markup", :with => '50%' + fill_in "description", :with => 'Need to fly to NYC for the week' + end + end click_button "Save" @@ -386,5 +446,8 @@ class DeliverablesEditTest < ActionController::IntegrationTest assert_equal 3, @retainer_deliverable.overhead_budgets.count assert_equal [100, nil, nil], @retainer_deliverable.overhead_budgets.collect(&:hours) assert_equal [100, nil, nil], @retainer_deliverable.overhead_budgets.collect(&:budget) + + assert_equal 3, @retainer_deliverable.fixed_budgets.count + assert_equal [600, nil, nil], @retainer_deliverable.fixed_budgets.collect(&:budget) end end From 294c88f11d2377bb7dc97f171e5dd6d39c8b0a46 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 17 Sep 2010 13:16:59 -0700 Subject: [PATCH 05/16] [#4477] Hook up FixedBudgets to Contract#fixed_budget and #fixed_markup_budget --- app/models/contract.rb | 14 +++++++++++-- app/models/deliverable.rb | 9 ++++++++ app/views/contracts/show.html.erb | 2 +- config/locales/en.yml | 4 ++-- test/unit/contract_test.rb | 34 +++++++++++++++++++++++++++++++ 5 files changed, 58 insertions(+), 5 deletions(-) diff --git a/app/models/contract.rb b/app/models/contract.rb index 0e65756..2db8ae4 100644 --- a/app/models/contract.rb +++ b/app/models/contract.rb @@ -36,8 +36,8 @@ class Contract < ActiveRecord::Base named_scope :by_name, {:order => "#{Contract.table_name}.name ASC"} [:status, :contract_type, - :fixed_spent, :fixed_budget, - :markup_spent, :markup_budget, + :fixed_spent, + :fixed_markup_spent, :discount_spent, :discount_budget ].each do |mthd| define_method(mthd) { "TODO in later release" } @@ -96,6 +96,16 @@ class Contract < ActiveRecord::Base end alias_method :profit_spent, :profit_left + # OPTIMIZE: N+1 + def fixed_budget + deliverables.inject(0) {|total, deliverable| total += deliverable.fixed_budget_total } + end + + # OPTIMIZE: N+1 + def fixed_markup_budget + deliverables.inject(0) {|total, deliverable| total += deliverable.fixed_markup_budget_total } + end + def after_initialize self.executed = false unless self.executed.present? end diff --git a/app/models/deliverable.rb b/app/models/deliverable.rb index 9f2f677..d9f356e 100644 --- a/app/models/deliverable.rb +++ b/app/models/deliverable.rb @@ -88,6 +88,15 @@ class Deliverable < ActiveRecord::Base issues.inject(0) {|total, issue| total += issue.spent_hours } end + def fixed_budget_total(date=nil) + fixed_budgets.sum(:budget) + end + + # OPTIMIZE: N+1 + def fixed_markup_budget_total(date=nil) + fixed_budgets.inject(0) {|total, fixed_budget| total += fixed_budget.markup_value } + end + def filter_by_date(date=nil, &block) block.call end diff --git a/app/views/contracts/show.html.erb b/app/views/contracts/show.html.erb index 55a4254..bc54681 100644 --- a/app/views/contracts/show.html.erb +++ b/app/views/contracts/show.html.erb @@ -44,7 +44,7 @@ <%= show_budget_field(resource, :labor_spent, :labor_budget, :format => :format_value_field_for_contracts, :html_options => {:class => 'contract-labor'}, :label_html_options => {:width => '46%'}) %> <%= show_budget_field(resource, :overhead_spent, :overhead_budget, :format => :format_value_field_for_contracts, :html_options => {:class => 'contract-overhead'}) %> <%= show_budget_field(resource, :fixed_spent, :fixed_budget, :format => :format_value_field_for_contracts, :html_options => {:class => 'contract-fixed'}) %> - <%= show_budget_field(resource, :markup_spent, :markup_budget, :format => :format_value_field_for_contracts, :html_options => {:class => 'contract-markup'}) %> + <%= show_budget_field(resource, :fixed_markup_spent, :fixed_markup_budget, :format => :format_value_field_for_contracts, :html_options => {:class => 'contract-markup'}) %> <%= show_budget_field(resource, :profit_spent, :profit_budget, :format => :format_value_field_for_contracts, :html_options => {:class => 'contract-profit'}) %> <%= show_budget_field(resource, :discount_spent, :discount_budget, :format => :format_value_field_for_contracts, :html_options => {:class => 'contract-discount'}) %> diff --git a/config/locales/en.yml b/config/locales/en.yml index 64c8cad..5dd440e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -40,8 +40,8 @@ en: field_fixed_spent: "Fixed" field_labor_budget: "Labor" field_labor_spent: "Labor" - field_markup_budget: "Markup" - field_markup_spent: "Markup" + field_fixed_markup_budget: "Markup" + field_fixed_markup_spent: "Markup" field_overhead_budget: "Overhead" field_overhead_spent: "Overhead" field_profit_budget: "Profit" diff --git a/test/unit/contract_test.rb b/test/unit/contract_test.rb index db441b2..b993620 100644 --- a/test/unit/contract_test.rb +++ b/test/unit/contract_test.rb @@ -254,4 +254,38 @@ class ContractTest < ActiveSupport::TestCase end end + + context "#fixed_budget" do + should "sum all fixed budget amounts on the Deliverables" do + contract = Contract.generate! + contract.deliverables << @deliverable_1 = FixedDeliverable.generate! + FixedBudget.generate!(:deliverable => @deliverable_1, :budget => '$1,000') + contract.deliverables << @deliverable_2 = HourlyDeliverable.generate! + FixedBudget.generate!(:deliverable => @deliverable_2, :budget => '$2,000') + + assert_equal 3000, contract.fixed_budget + end + end + + context "#fixed_spent" do + should "QUESTION: how to compute the amount spent" + end + + context "#fixed_markup_budget" do + should "sum all fixed budget markup values on the Deliverables" do + contract = Contract.generate! + contract.deliverables << @deliverable_1 = FixedDeliverable.generate! + FixedBudget.generate!(:deliverable => @deliverable_1, :budget => '$1,000', :markup => '$100') + contract.deliverables << @deliverable_2 = HourlyDeliverable.generate! + FixedBudget.generate!(:deliverable => @deliverable_2, :budget => '$2,000', :markup => '200%') + + assert_equal (100) + (2.00 * 2000), contract.fixed_markup_budget + end + + end + + context "#fixed_markup_spent" do + should "QUESTION: how to compute the amount spent" + end + end From 86be29cecc715ba3305491faa2df31bccb34d7e8 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 17 Sep 2010 13:27:35 -0700 Subject: [PATCH 06/16] [#4477] Show the total fixed budget in the deliverable row --- app/views/contracts/show.html.erb | 2 +- test/integration/contracts_show_test.rb | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/app/views/contracts/show.html.erb b/app/views/contracts/show.html.erb index bc54681..864236d 100644 --- a/app/views/contracts/show.html.erb +++ b/app/views/contracts/show.html.erb @@ -104,7 +104,7 @@ <%= h deliverable.manager.try(:name) %> <%= format_budget_for_deliverable(deliverable, deliverable.labor_budget_spent, deliverable.labor_budget_total, :class => 'labor') %> <%= format_budget_for_deliverable(deliverable, deliverable.overhead_spent, deliverable.overhead_budget_total, :class => 'overhead') %> - <%= format_budget_for_deliverable(deliverable, 0, 0) %><%# TODO: Release 2, Fixed Budgets %> + <%= format_budget_for_deliverable(deliverable, 0, deliverable.fixed_budget_total, :class => 'fixed') %> <% end %> diff --git a/test/integration/contracts_show_test.rb b/test/integration/contracts_show_test.rb index 08ea047..e3494f5 100644 --- a/test/integration/contracts_show_test.rb +++ b/test/integration/contracts_show_test.rb @@ -210,6 +210,23 @@ class ContractsShowTest < ActionController::IntegrationTest end + should "show the total fixed budget for a Deliverable" do + @manager = User.generate! + + @deliverable1 = FixedDeliverable.generate!(:contract => @contract, :manager => @manager) + + FixedBudget.generate!(:deliverable => @deliverable1, :budget => '$1,000', :markup => '$100') + FixedBudget.generate!(:deliverable => @deliverable1, :budget => '$2,000', :markup => '200%') + + visit_contract_page(@contract) + assert_select "table#deliverables" do + assert_select "td.fixed", :text => /3,000/ + end + + end + + should "QUESTION: show the total fixed budget spent for a Deliverable" + should "show the current period for a Retainer" do today_mock = Date.new(2010,2,15) Date.stubs(:today).returns(today_mock) From ed7536897ee30d710db84821090caf9de0c66520 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 17 Sep 2010 13:38:44 -0700 Subject: [PATCH 07/16] [#4477] Show each fixed budget item in the deliverable details --- app/views/deliverables/_details_row.html.erb | 11 +++++++- test/integration/contracts_show_test.rb | 27 ++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/app/views/deliverables/_details_row.html.erb b/app/views/deliverables/_details_row.html.erb index c4d6aea..8208f4a 100644 --- a/app/views/deliverables/_details_row.html.erb +++ b/app/views/deliverables/_details_row.html.erb @@ -62,7 +62,16 @@ <%= h(format_value_field_for_contracts(deliverable.overhead_budget_total(period))) %> TODO: Release 2 / TODO hrs - <%# TODO: Release 2, Fixed %> + + <% deliverable.fixed_budgets.each do |fixed_budget| %> + + <%= h(fixed_budget.title) %> + 0 + <%= h(format_value_field_for_contracts(fixed_budget.budget)) %> + + + <% end %> + <%# TODO: Release 2, Markup %> Profit diff --git a/test/integration/contracts_show_test.rb b/test/integration/contracts_show_test.rb index e3494f5..ea588af 100644 --- a/test/integration/contracts_show_test.rb +++ b/test/integration/contracts_show_test.rb @@ -227,6 +227,33 @@ class ContractsShowTest < ActionController::IntegrationTest should "QUESTION: show the total fixed budget spent for a Deliverable" + should "show each fixed budget item in the details for the Deliverable" do + @manager = User.generate! + + @deliverable1 = FixedDeliverable.generate!(:contract => @contract, :manager => @manager) + + @budget1 = FixedBudget.generate!(:deliverable => @deliverable1, :title => 'Item 1', :budget => '$1,000', :markup => '$100') + @budget2 = FixedBudget.generate!(:deliverable => @deliverable1, :title => 'Item 2', :budget => '$2,000', :markup => '200%') + + visit_contract_page(@contract) + assert_select "table#deliverables" do + assert_select "#deliverable_details_#{@deliverable1.id}" do + assert_select "tr#fixed_budget_#{@budget1.id}" do + assert_select 'td.fixed_title', :text => /#{@budget1.title}/ + assert_select 'td.fixed_budget_spent', :text => '0' + assert_select 'td.fixed_budget_total', :text => '1,000' + end + + assert_select "tr#fixed_budget_#{@budget2.id}" do + assert_select 'td.fixed_title', :text => /#{@budget2.title}/ + assert_select 'td.fixed_budget_spent', :text => '0' + assert_select 'td.fixed_budget_total', :text => '2,000' + end + end + end + + end + should "show the current period for a Retainer" do today_mock = Date.new(2010,2,15) Date.stubs(:today).returns(today_mock) From 081df7874da70920b0f7d835df7860d343b90b6b Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 17 Sep 2010 13:43:35 -0700 Subject: [PATCH 08/16] [#4477] Added the total FixedBudget markup to the deliverable details --- app/views/deliverables/_details_row.html.erb | 8 +++++++- test/integration/contracts_show_test.rb | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/app/views/deliverables/_details_row.html.erb b/app/views/deliverables/_details_row.html.erb index 8208f4a..6e2b771 100644 --- a/app/views/deliverables/_details_row.html.erb +++ b/app/views/deliverables/_details_row.html.erb @@ -72,7 +72,13 @@ <% end %> - <%# TODO: Release 2, Markup %> + + <%= l(:field_markup) %> + 0 + <%= h(format_value_field_for_contracts(deliverable.fixed_markup_budget_total(period))) %> + + + Profit <%= h(format_value_field_for_contracts(deliverable.profit_left(period))) %> diff --git a/test/integration/contracts_show_test.rb b/test/integration/contracts_show_test.rb index ea588af..3d57987 100644 --- a/test/integration/contracts_show_test.rb +++ b/test/integration/contracts_show_test.rb @@ -254,6 +254,23 @@ class ContractsShowTest < ActionController::IntegrationTest end + should "show the total fixed markup budget in the details for the Deliverable" do + @manager = User.generate! + + @deliverable1 = FixedDeliverable.generate!(:contract => @contract, :manager => @manager) + + @budget1 = FixedBudget.generate!(:deliverable => @deliverable1, :title => 'Item 1', :budget => '$1,000', :markup => '$100') + @budget2 = FixedBudget.generate!(:deliverable => @deliverable1, :title => 'Item 2', :budget => '$2,000', :markup => '200%') + + visit_contract_page(@contract) + assert_select "table#deliverables" do + assert_select "#deliverable_details_#{@deliverable1.id}" do + assert_select 'td.fixed_markup_budget_spent', :text => '0' + assert_select 'td.fixed_markup_budget_total', :text => '4,100' + end + end + end + should "show the current period for a Retainer" do today_mock = Date.new(2010,2,15) Date.stubs(:today).returns(today_mock) From 55c9f93c6c8663fe83a81034a5feab03482d2ede Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 17 Sep 2010 14:15:08 -0700 Subject: [PATCH 09/16] [#4477] Change Retainers to scope #fixed_budget_total and #fixed_markup_budget_total by date --- app/models/retainer_deliverable.rb | 23 ++++++++ test/unit/retainer_deliverable_test.rb | 74 ++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/app/models/retainer_deliverable.rb b/app/models/retainer_deliverable.rb index 25fa354..9831474 100644 --- a/app/models/retainer_deliverable.rb +++ b/app/models/retainer_deliverable.rb @@ -122,6 +122,29 @@ class RetainerDeliverable < HourlyDeliverable end end + def fixed_budget_total(date=nil) + case scope_date_status(date) + when :in + fixed_budgets.sum(:budget, :conditions => {:year => date.year, :month => date.month}) + when :out + 0 + else + super + end + end + + def fixed_markup_budget_total(date=nil) + case scope_date_status(date) + when :in + fixed_budgets. + all(:conditions => {:year => date.year, :month => date.month}). + inject(0) {|total, fixed_budget| total += fixed_budget.markup_value } + when :out + 0 + else + super + end + end def total_spent(date=nil) case scope_date_status(date) when :in diff --git a/test/unit/retainer_deliverable_test.rb b/test/unit/retainer_deliverable_test.rb index 7ace8a5..ea67a46 100644 --- a/test/unit/retainer_deliverable_test.rb +++ b/test/unit/retainer_deliverable_test.rb @@ -476,4 +476,78 @@ class RetainerDeliverableTest < ActiveSupport::TestCase end end + + context "#fixed_budget_total" do + setup do + @contract = Contract.generate!(:billable_rate => 100) + @deliverable = RetainerDeliverable.generate!(:start_date => '2010-01-01', :end_date => '2010-03-31', :contract => @contract) + @deliverable.fixed_budgets << FixedBudget.spawn(:budget => 1000) + @deliverable.fixed_budgets << FixedBudget.spawn(:budget => 2000) + @deliverable.save! + + assert_equal 3000 * 3, @deliverable.fixed_budget_total + end + + context "with a empty period" do + should "use all periods" do + assert_equal 9000, @deliverable.fixed_budget_total(nil) + end + end + + context "with a period out of the retainer range" do + should "filter the records" do + assert_equal 0, @deliverable.fixed_budget_total(Date.new(2011,1,1)) + end + end + + context "with an invalid period" do + should "return 0" do + assert_equal 0, @deliverable.fixed_budget_total('1') + end + end + + context "with a period in the retainer range" do + should "filter the records" do + assert_equal 3000, @deliverable.fixed_budget_total(Date.new(2010,2,1)) + end + end + + end + + context "#fixed_markup_budget_total" do + setup do + @contract = Contract.generate!(:billable_rate => 100) + @deliverable = RetainerDeliverable.generate!(:start_date => '2010-01-01', :end_date => '2010-03-31', :contract => @contract) + @deliverable.fixed_budgets << FixedBudget.spawn(:budget => 1000, :markup => '50%') + @deliverable.fixed_budgets << FixedBudget.spawn(:budget => 2000, :markup => '$1000') + @deliverable.save! + + assert_equal (500 + 1000) * 3, @deliverable.fixed_markup_budget_total + end + + context "with a empty period" do + should "use all periods" do + assert_equal 4500, @deliverable.fixed_markup_budget_total(nil) + end + end + + context "with a period out of the retainer range" do + should "filter the records" do + assert_equal 0, @deliverable.fixed_markup_budget_total(Date.new(2011,1,1)) + end + end + + context "with an invalid period" do + should "return 0" do + assert_equal 0, @deliverable.fixed_markup_budget_total('1') + end + end + + context "with a period in the retainer range" do + should "filter the records" do + assert_equal 1500, @deliverable.fixed_markup_budget_total(Date.new(2010,2,1)) + end + end + + end end From 67dd75a9808dfadf8888be890bd2a0957a6f78cc Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 17 Sep 2010 14:23:29 -0700 Subject: [PATCH 10/16] [#4477] Skip blank FixedBudget items in the deliverable details --- app/models/fixed_budget.rb | 8 +++++++- app/views/deliverables/_details_row.html.erb | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/app/models/fixed_budget.rb b/app/models/fixed_budget.rb index 9ea971c..bfbcb56 100644 --- a/app/models/fixed_budget.rb +++ b/app/models/fixed_budget.rb @@ -37,5 +37,11 @@ class FixedBudget < ActiveRecord::Base def straight_markup? markup && markup.match(/\$/) end - + + # Is this a blank budget item. Retainers will create blank ones when + # they are copied. (RetainerDeliverable#create_budgets_for_periods) + def blank_record? + return true if new_record? + return title.blank? && budget.blank? && markup.blank? + end end diff --git a/app/views/deliverables/_details_row.html.erb b/app/views/deliverables/_details_row.html.erb index 6e2b771..b2a6ccb 100644 --- a/app/views/deliverables/_details_row.html.erb +++ b/app/views/deliverables/_details_row.html.erb @@ -64,6 +64,7 @@ <% deliverable.fixed_budgets.each do |fixed_budget| %> + <% next if fixed_budget.blank_record? %> <%= h(fixed_budget.title) %> 0 From d78e7b1dc342c94e477d03ee838295bc2203a769 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 17 Sep 2010 14:51:48 -0700 Subject: [PATCH 11/16] [#4477] Scope fixed budget items by period too (for Retainers) --- app/models/fixed_budget.rb | 8 ++++++++ app/views/deliverables/_details_row.html.erb | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/models/fixed_budget.rb b/app/models/fixed_budget.rb index bfbcb56..982067a 100644 --- a/app/models/fixed_budget.rb +++ b/app/models/fixed_budget.rb @@ -15,6 +15,14 @@ class FixedBudget < ActiveRecord::Base end end + named_scope :by_period, lambda {|date| + if date + { + :conditions => {:year => date.year, :month => date.month} + } + end + } + def markup_value return 0 if budget.blank? || markup.blank? diff --git a/app/views/deliverables/_details_row.html.erb b/app/views/deliverables/_details_row.html.erb index b2a6ccb..ef7104a 100644 --- a/app/views/deliverables/_details_row.html.erb +++ b/app/views/deliverables/_details_row.html.erb @@ -63,7 +63,7 @@ TODO: Release 2 / TODO hrs - <% deliverable.fixed_budgets.each do |fixed_budget| %> + <% deliverable.fixed_budgets.by_period(period).each do |fixed_budget| %> <% next if fixed_budget.blank_record? %> <%= h(fixed_budget.title) %> From 2c04ef4f452263a6de6471ab8faad9772317004e Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 17 Sep 2010 15:22:53 -0700 Subject: [PATCH 12/16] [#4477] Add FixedBudget items into the total and profit Deliverable calculations --- app/models/fixed_deliverable.rb | 2 +- app/models/hourly_deliverable.rb | 6 ++++-- test/unit/fixed_deliverable_test.rb | 3 ++- test/unit/hourly_deliverable_test.rb | 10 ++++++---- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/app/models/fixed_deliverable.rb b/app/models/fixed_deliverable.rb index 52e6a11..644b751 100644 --- a/app/models/fixed_deliverable.rb +++ b/app/models/fixed_deliverable.rb @@ -23,7 +23,7 @@ class FixedDeliverable < Deliverable # The amount of profit that is budgeted for this deliverable. # Profit = Total - ( Labor + Overhead + Fixed + Markup ) def profit_budget(date=nil) - budgets = labor_budget_total(date) + overhead_budget_total(date) + budgets = labor_budget_total(date) + overhead_budget_total(date) + fixed_budget_total(date) + fixed_markup_budget_total(date) (total(date) || 0.0) - budgets end diff --git a/app/models/hourly_deliverable.rb b/app/models/hourly_deliverable.rb index 5fb3792..dfb1096 100644 --- a/app/models/hourly_deliverable.rb +++ b/app/models/hourly_deliverable.rb @@ -14,12 +14,14 @@ class HourlyDeliverable < Deliverable 'H' end + # Total = ( Labor Hours * Billing Rate ) + ( Fixed + Markup ) def total(date=nil) return 0 if contract.nil? return 0 if contract.billable_rate.blank? return 0 if labor_budgets.count == 0 && overhead_budgets.count == 0 - return contract.billable_rate * labor_budget_hours(date) + fixed_budget_amount = fixed_budget_total(date) + fixed_markup_budget_total(date) + return (contract.billable_rate * labor_budget_hours(date)) + fixed_budget_amount end # Total amount to be billed on the deliverable, using the total time logged @@ -50,7 +52,7 @@ class HourlyDeliverable < Deliverable # The amount of profit that is budgeted for this deliverable # Profit = Total - ( Labor + Overhead + Fixed + Markup ) def profit_budget(date=nil) - budgets = labor_budget_total(date) + overhead_budget_total(date) + budgets = labor_budget_total(date) + overhead_budget_total(date) + fixed_budget_total(date) + fixed_markup_budget_total(date) (total(date) || 0.0) - budgets end diff --git a/test/unit/fixed_deliverable_test.rb b/test/unit/fixed_deliverable_test.rb index b480d76..a55635a 100644 --- a/test/unit/fixed_deliverable_test.rb +++ b/test/unit/fixed_deliverable_test.rb @@ -13,8 +13,9 @@ class FixedDeliverableTest < ActiveSupport::TestCase LaborBudget.generate!(:deliverable => deliverable, :budget => 200) LaborBudget.generate!(:deliverable => deliverable, :budget => 200) OverheadBudget.generate!(:deliverable => deliverable, :budget => 200) + FixedBudget.generate!(:deliverable => deliverable, :budget => '$100', :markup => '50%') # $50 markup - assert_equal 400, deliverable.profit_budget + assert_equal 400 - 150, deliverable.profit_budget end should "be 0 if there is no total" do diff --git a/test/unit/hourly_deliverable_test.rb b/test/unit/hourly_deliverable_test.rb index 9c51191..6f2c4d7 100644 --- a/test/unit/hourly_deliverable_test.rb +++ b/test/unit/hourly_deliverable_test.rb @@ -20,13 +20,14 @@ class HourlyDeliverableTest < ActiveSupport::TestCase assert_equal 0, d.total end - should "multiply the total number of labor budget hours by the contract billable rate" do + should "multiply the total number of labor budget hours by the contract billable rate and add the fixed budget and markup" do contract = Contract.generate!(:billable_rate => 100.0) d = HourlyDeliverable.generate!(:contract => contract) d.labor_budgets << LaborBudget.generate!(:hours => 10) d.overhead_budgets << OverheadBudget.generate!(:hours => 20) + d.fixed_budgets << FixedBudget.generate!(:budget => '$100', :markup => '50%') # $50 markup - assert_equal 100.0 * 10, d.total + assert_equal (100.0 * 10) + (100 + 50), d.total end end @@ -86,9 +87,10 @@ class HourlyDeliverableTest < ActiveSupport::TestCase LaborBudget.generate!(:deliverable => @deliverable, :hours => 5, :budget => 250) LaborBudget.generate!(:deliverable => @deliverable, :hours => 5, :budget => 250) OverheadBudget.generate!(:deliverable => @deliverable, :hours => 3, :budget => 225) + FixedBudget.generate!(:deliverable => @deliverable, :budget => '$100', :markup => '50%') # $50 markup - assert_equal 1500, @deliverable.total - assert_equal 1500 - (225 + 250 + 250), @deliverable.profit_budget + assert_equal 1650, @deliverable.total # has the FixedBudget items added to the total also + assert_equal 1650 - (225 + 250 + 250 + 100 + 50), @deliverable.profit_budget end end From f8270498f3e614330f3c82be0a45f53edd888496 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 17 Sep 2010 15:37:30 -0700 Subject: [PATCH 13/16] [#4477] Add a simple title/tooltip for the FixedBudget description --- app/views/deliverables/_details_row.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/deliverables/_details_row.html.erb b/app/views/deliverables/_details_row.html.erb index ef7104a..2713db5 100644 --- a/app/views/deliverables/_details_row.html.erb +++ b/app/views/deliverables/_details_row.html.erb @@ -66,7 +66,7 @@ <% deliverable.fixed_budgets.by_period(period).each do |fixed_budget| %> <% next if fixed_budget.blank_record? %> - <%= h(fixed_budget.title) %> + <%= h(fixed_budget.title) %> 0 <%= h(format_value_field_for_contracts(fixed_budget.budget)) %> From d4de581b3c2980039967982eba34bbb6b03c2152 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Wed, 22 Sep 2010 10:49:36 -0700 Subject: [PATCH 14/16] [#4477] Added a paid field to track when a FixedBudget is spent --- app/views/deliverables/_finance_form.html.erb | 6 ++++++ config/locales/en.yml | 1 + db/migrate/017_add_paid_to_fixed_budgets.rb | 10 ++++++++++ test/integration/deliverables_edit_test.rb | 4 +++- 4 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 db/migrate/017_add_paid_to_fixed_budgets.rb diff --git a/app/views/deliverables/_finance_form.html.erb b/app/views/deliverables/_finance_form.html.erb index 0942953..23e2798 100644 --- a/app/views/deliverables/_finance_form.html.erb +++ b/app/views/deliverables/_finance_form.html.erb @@ -85,6 +85,12 @@

    <%= fixed_budget.text_field(:markup) %> +

    + <%= fixed_budget.label(:paid, l(:field_paid), :style => 'display: none;') %><%# Hidden label :| %> + <%= l(:field_paid) %> +

    + <%= fixed_budget.check_box(:paid) %> + <%= fixed_budget.text_area(:description, :class => 'wiki-edit', :rows => '5', :id => "fixed-description#{fixed_budget.object.object_id}") %> <%= wikitoolbar_for "fixed-description#{fixed_budget.object.object_id}" %> diff --git a/config/locales/en.yml b/config/locales/en.yml index 5dd440e..c01cc94 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -72,3 +72,4 @@ en: text_flash_deliverable_destroyed: "Deliverable: {{name}} was successfully destroyed." field_budget: Budget field_markup: Markup + field_paid: Paid diff --git a/db/migrate/017_add_paid_to_fixed_budgets.rb b/db/migrate/017_add_paid_to_fixed_budgets.rb new file mode 100644 index 0000000..3508ff5 --- /dev/null +++ b/db/migrate/017_add_paid_to_fixed_budgets.rb @@ -0,0 +1,10 @@ +class AddPaidToFixedBudgets < ActiveRecord::Migration + def self.up + add_column :fixed_budgets, :paid, :boolean + add_index :fixed_budgets, :paid + end + + def self.down + remove_column :fixed_budgets, :paid + end +end diff --git a/test/integration/deliverables_edit_test.rb b/test/integration/deliverables_edit_test.rb index b139622..c7fd8fc 100644 --- a/test/integration/deliverables_edit_test.rb +++ b/test/integration/deliverables_edit_test.rb @@ -406,9 +406,11 @@ class DeliverablesEditTest < ActionController::IntegrationTest # * fixed title # * fixed budget # * fixed markup + # * fixed paid checkbox + # * fixed paid hidden field # * total (hidden) assert_select ".date-2010-01" do - assert_select "input", :count => 14 + assert_select "input", :count => 16 assert_select "textarea.wiki-edit", :count => 1 # Fixed description end From 4a7484e1eaefd313a4ce8d7783ba7eafba86e9ad Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Wed, 22 Sep 2010 11:27:42 -0700 Subject: [PATCH 15/16] [#4477] Added the amounts spent for FixedBudgets --- app/models/contract.rb | 14 +++- app/models/deliverable.rb | 9 +++ app/models/fixed_budget.rb | 10 +++ app/models/retainer_deliverable.rb | 26 +++++++ app/views/contracts/show.html.erb | 2 +- app/views/deliverables/_details_row.html.erb | 4 +- test/integration/contracts_show_test.rb | 22 ++++-- test/unit/contract_test.rb | 20 +++++- test/unit/retainer_deliverable_test.rb | 74 ++++++++++++++++++++ 9 files changed, 168 insertions(+), 13 deletions(-) diff --git a/app/models/contract.rb b/app/models/contract.rb index 2db8ae4..8552893 100644 --- a/app/models/contract.rb +++ b/app/models/contract.rb @@ -36,8 +36,6 @@ class Contract < ActiveRecord::Base named_scope :by_name, {:order => "#{Contract.table_name}.name ASC"} [:status, :contract_type, - :fixed_spent, - :fixed_markup_spent, :discount_spent, :discount_budget ].each do |mthd| define_method(mthd) { "TODO in later release" } @@ -100,12 +98,22 @@ class Contract < ActiveRecord::Base def fixed_budget deliverables.inject(0) {|total, deliverable| total += deliverable.fixed_budget_total } end - + + # OPTIMIZE: N+1 + def fixed_spent + deliverables.inject(0) {|total, deliverable| total += deliverable.fixed_budget_total_spent } + end + # OPTIMIZE: N+1 def fixed_markup_budget deliverables.inject(0) {|total, deliverable| total += deliverable.fixed_markup_budget_total } end + # OPTIMIZE: N+1 + def fixed_markup_spent + deliverables.inject(0) {|total, deliverable| total += deliverable.fixed_markup_budget_total_spent } + end + def after_initialize self.executed = false unless self.executed.present? end diff --git a/app/models/deliverable.rb b/app/models/deliverable.rb index d9f356e..692ed8d 100644 --- a/app/models/deliverable.rb +++ b/app/models/deliverable.rb @@ -92,11 +92,20 @@ class Deliverable < ActiveRecord::Base fixed_budgets.sum(:budget) end + def fixed_budget_total_spent(date=nil) + fixed_budgets.paid.sum(:budget) + end + # OPTIMIZE: N+1 def fixed_markup_budget_total(date=nil) fixed_budgets.inject(0) {|total, fixed_budget| total += fixed_budget.markup_value } end + # OPTIMIZE: N+1 + def fixed_markup_budget_total_spent(date=nil) + fixed_budgets.paid.inject(0) {|total, fixed_budget| total += fixed_budget.markup_value } + end + def filter_by_date(date=nil, &block) block.call end diff --git a/app/models/fixed_budget.rb b/app/models/fixed_budget.rb index 982067a..9a43013 100644 --- a/app/models/fixed_budget.rb +++ b/app/models/fixed_budget.rb @@ -23,6 +23,8 @@ class FixedBudget < ActiveRecord::Base end } + named_scope :paid, {:conditions => {:paid => true}} + def markup_value return 0 if budget.blank? || markup.blank? @@ -38,6 +40,14 @@ class FixedBudget < ActiveRecord::Base end + def budget_spent + if paid? + budget + else + 0 + end + end + def percent_markup? markup && markup.match(/%/) end diff --git a/app/models/retainer_deliverable.rb b/app/models/retainer_deliverable.rb index 9831474..c77890e 100644 --- a/app/models/retainer_deliverable.rb +++ b/app/models/retainer_deliverable.rb @@ -133,6 +133,17 @@ class RetainerDeliverable < HourlyDeliverable end end + def fixed_budget_total_spent(date=nil) + case scope_date_status(date) + when :in + fixed_budgets.paid.sum(:budget, :conditions => {:year => date.year, :month => date.month}) + when :out + 0 + else + super + end + end + def fixed_markup_budget_total(date=nil) case scope_date_status(date) when :in @@ -145,6 +156,21 @@ class RetainerDeliverable < HourlyDeliverable super end end + + def fixed_markup_budget_total_spent(date=nil) + case scope_date_status(date) + when :in + fixed_budgets. + paid. + all(:conditions => {:year => date.year, :month => date.month}). + inject(0) {|total, fixed_budget| total += fixed_budget.markup_value } + when :out + 0 + else + super + end + end + def total_spent(date=nil) case scope_date_status(date) when :in diff --git a/app/views/contracts/show.html.erb b/app/views/contracts/show.html.erb index 864236d..2149e11 100644 --- a/app/views/contracts/show.html.erb +++ b/app/views/contracts/show.html.erb @@ -104,7 +104,7 @@ <%= h deliverable.manager.try(:name) %> <%= format_budget_for_deliverable(deliverable, deliverable.labor_budget_spent, deliverable.labor_budget_total, :class => 'labor') %> <%= format_budget_for_deliverable(deliverable, deliverable.overhead_spent, deliverable.overhead_budget_total, :class => 'overhead') %> - <%= format_budget_for_deliverable(deliverable, 0, deliverable.fixed_budget_total, :class => 'fixed') %> + <%= format_budget_for_deliverable(deliverable, deliverable.fixed_budget_total_spent, deliverable.fixed_budget_total, :class => 'fixed') %> <% end %> diff --git a/app/views/deliverables/_details_row.html.erb b/app/views/deliverables/_details_row.html.erb index 2713db5..ce52817 100644 --- a/app/views/deliverables/_details_row.html.erb +++ b/app/views/deliverables/_details_row.html.erb @@ -67,7 +67,7 @@ <% next if fixed_budget.blank_record? %> <%= h(fixed_budget.title) %> - 0 + <%= h(format_value_field_for_contracts(fixed_budget.budget_spent)) %> <%= h(format_value_field_for_contracts(fixed_budget.budget)) %> @@ -75,7 +75,7 @@ <%= l(:field_markup) %> - 0 + <%= h(format_value_field_for_contracts(deliverable.fixed_markup_budget_total_spent(period))) %> <%= h(format_value_field_for_contracts(deliverable.fixed_markup_budget_total(period))) %> diff --git a/test/integration/contracts_show_test.rb b/test/integration/contracts_show_test.rb index 3d57987..bb3dccd 100644 --- a/test/integration/contracts_show_test.rb +++ b/test/integration/contracts_show_test.rb @@ -225,14 +225,26 @@ class ContractsShowTest < ActionController::IntegrationTest end - should "QUESTION: show the total fixed budget spent for a Deliverable" + should "show the total fixed budget spent for a Deliverable" do + @manager = User.generate! + + @deliverable1 = FixedDeliverable.generate!(:contract => @contract, :manager => @manager) + + FixedBudget.generate!(:deliverable => @deliverable1, :budget => '$1,000', :markup => '$100', :paid => true) + FixedBudget.generate!(:deliverable => @deliverable1, :budget => '$2,000', :markup => '200%') + + visit_contract_page(@contract) + assert_select "table#deliverables" do + assert_select "td.fixed.spent-amount", :text => /1,000/ + end + end should "show each fixed budget item in the details for the Deliverable" do @manager = User.generate! @deliverable1 = FixedDeliverable.generate!(:contract => @contract, :manager => @manager) - @budget1 = FixedBudget.generate!(:deliverable => @deliverable1, :title => 'Item 1', :budget => '$1,000', :markup => '$100') + @budget1 = FixedBudget.generate!(:deliverable => @deliverable1, :title => 'Item 1', :budget => '$1,000', :markup => '$100', :paid => true) @budget2 = FixedBudget.generate!(:deliverable => @deliverable1, :title => 'Item 2', :budget => '$2,000', :markup => '200%') visit_contract_page(@contract) @@ -240,7 +252,7 @@ class ContractsShowTest < ActionController::IntegrationTest assert_select "#deliverable_details_#{@deliverable1.id}" do assert_select "tr#fixed_budget_#{@budget1.id}" do assert_select 'td.fixed_title', :text => /#{@budget1.title}/ - assert_select 'td.fixed_budget_spent', :text => '0' + assert_select 'td.fixed_budget_spent', :text => '1,000' assert_select 'td.fixed_budget_total', :text => '1,000' end @@ -259,13 +271,13 @@ class ContractsShowTest < ActionController::IntegrationTest @deliverable1 = FixedDeliverable.generate!(:contract => @contract, :manager => @manager) - @budget1 = FixedBudget.generate!(:deliverable => @deliverable1, :title => 'Item 1', :budget => '$1,000', :markup => '$100') + @budget1 = FixedBudget.generate!(:deliverable => @deliverable1, :title => 'Item 1', :budget => '$1,000', :markup => '$100', :paid => true) @budget2 = FixedBudget.generate!(:deliverable => @deliverable1, :title => 'Item 2', :budget => '$2,000', :markup => '200%') visit_contract_page(@contract) assert_select "table#deliverables" do assert_select "#deliverable_details_#{@deliverable1.id}" do - assert_select 'td.fixed_markup_budget_spent', :text => '0' + assert_select 'td.fixed_markup_budget_spent', :text => '100' assert_select 'td.fixed_markup_budget_total', :text => '4,100' end end diff --git a/test/unit/contract_test.rb b/test/unit/contract_test.rb index b993620..c3daeae 100644 --- a/test/unit/contract_test.rb +++ b/test/unit/contract_test.rb @@ -268,7 +268,15 @@ class ContractTest < ActiveSupport::TestCase end context "#fixed_spent" do - should "QUESTION: how to compute the amount spent" + should "sum all fixed budget amounts on the Deliverables which are paid" do + contract = Contract.generate! + contract.deliverables << @deliverable_1 = FixedDeliverable.generate! + FixedBudget.generate!(:deliverable => @deliverable_1, :budget => '$1,000', :paid => true) + contract.deliverables << @deliverable_2 = HourlyDeliverable.generate! + FixedBudget.generate!(:deliverable => @deliverable_2, :budget => '$2,000') + + assert_equal 1000, contract.fixed_spent + end end context "#fixed_markup_budget" do @@ -285,7 +293,15 @@ class ContractTest < ActiveSupport::TestCase end context "#fixed_markup_spent" do - should "QUESTION: how to compute the amount spent" + should "sum all fixed budget markup values on the Deliverables which are paid" do + contract = Contract.generate! + contract.deliverables << @deliverable_1 = FixedDeliverable.generate! + FixedBudget.generate!(:deliverable => @deliverable_1, :budget => '$1,000', :markup => '$100', :paid => true) + contract.deliverables << @deliverable_2 = HourlyDeliverable.generate! + FixedBudget.generate!(:deliverable => @deliverable_2, :budget => '$2,000', :markup => '200%') + + assert_equal (100) + (0), contract.fixed_markup_spent + end end end diff --git a/test/unit/retainer_deliverable_test.rb b/test/unit/retainer_deliverable_test.rb index ea67a46..4fe5e33 100644 --- a/test/unit/retainer_deliverable_test.rb +++ b/test/unit/retainer_deliverable_test.rb @@ -514,6 +514,43 @@ class RetainerDeliverableTest < ActiveSupport::TestCase end + context "#fixed_budget_total_spent" do + setup do + @contract = Contract.generate!(:billable_rate => 100) + @deliverable = RetainerDeliverable.generate!(:start_date => '2010-01-01', :end_date => '2010-03-31', :contract => @contract) + @deliverable.fixed_budgets << FixedBudget.spawn(:budget => 1000, :paid => true) + @deliverable.fixed_budgets << FixedBudget.spawn(:budget => 2000) + @deliverable.save! + + assert_equal 1000 * 3, @deliverable.fixed_budget_total_spent + end + + context "with a empty period" do + should "use all periods" do + assert_equal 3000, @deliverable.fixed_budget_total_spent(nil) + end + end + + context "with a period out of the retainer range" do + should "filter the records" do + assert_equal 0, @deliverable.fixed_budget_total_spent(Date.new(2011,1,1)) + end + end + + context "with an invalid period" do + should "return 0" do + assert_equal 0, @deliverable.fixed_budget_total_spent('1') + end + end + + context "with a period in the retainer range" do + should "filter the records" do + assert_equal 1000, @deliverable.fixed_budget_total_spent(Date.new(2010,2,1)) + end + end + + end + context "#fixed_markup_budget_total" do setup do @contract = Contract.generate!(:billable_rate => 100) @@ -550,4 +587,41 @@ class RetainerDeliverableTest < ActiveSupport::TestCase end end + + context "#fixed_markup_budget_total_spent" do + setup do + @contract = Contract.generate!(:billable_rate => 100) + @deliverable = RetainerDeliverable.generate!(:start_date => '2010-01-01', :end_date => '2010-03-31', :contract => @contract) + @deliverable.fixed_budgets << FixedBudget.spawn(:budget => 1000, :markup => '50%', :paid => true) + @deliverable.fixed_budgets << FixedBudget.spawn(:budget => 2000, :markup => '$1000') + @deliverable.save! + + assert_equal (500) * 3, @deliverable.fixed_markup_budget_total_spent + end + + context "with a empty period" do + should "use all periods" do + assert_equal 1500, @deliverable.fixed_markup_budget_total_spent(nil) + end + end + + context "with a period out of the retainer range" do + should "filter the records" do + assert_equal 0, @deliverable.fixed_markup_budget_total_spent(Date.new(2011,1,1)) + end + end + + context "with an invalid period" do + should "return 0" do + assert_equal 0, @deliverable.fixed_markup_budget_total_spent('1') + end + end + + context "with a period in the retainer range" do + should "filter the records" do + assert_equal 500, @deliverable.fixed_markup_budget_total_spent(Date.new(2010,2,1)) + end + end + + end end From 967ef6bc7a50ab053200a5e32d37eddea65ede21 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Wed, 22 Sep 2010 11:41:14 -0700 Subject: [PATCH 16/16] [#4777] Add fixed budgets to the profit_left calculations --- app/models/fixed_deliverable.rb | 4 ++-- app/models/hourly_deliverable.rb | 4 ++-- test/unit/contract_test.rb | 5 +++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/app/models/fixed_deliverable.rb b/app/models/fixed_deliverable.rb index 644b751..090861d 100644 --- a/app/models/fixed_deliverable.rb +++ b/app/models/fixed_deliverable.rb @@ -28,9 +28,9 @@ class FixedDeliverable < Deliverable end # The amount of money remaining after expenses have been taken out - # Profit left = Total - Labor spent - Overhead spent + # Profit left = Total - Labor spent - Overhead spent - Fixed - Markup def profit_left(date=nil) - total_spent(date) - labor_budget_spent(date) - overhead_spent(date) + total_spent(date) - labor_budget_spent(date) - overhead_spent(date) - fixed_budget_total_spent(date) - fixed_markup_budget_total_spent(date) end # Hardcoded value used as a wrapper for the old Budget plugin API. diff --git a/app/models/hourly_deliverable.rb b/app/models/hourly_deliverable.rb index dfb1096..4757883 100644 --- a/app/models/hourly_deliverable.rb +++ b/app/models/hourly_deliverable.rb @@ -57,8 +57,8 @@ class HourlyDeliverable < Deliverable end # The amount of money remaining after expenses have been taken out - # Profit left = Total - Labor spent - Overhead spent + # Profit left = Total - Labor spent - Overhead spent - Fixed - Markup def profit_left(date=nil) - total_spent(date) - labor_budget_spent(date) - overhead_spent(date) + total_spent(date) - labor_budget_spent(date) - overhead_spent(date) - fixed_budget_total_spent(date) - fixed_markup_budget_total_spent(date) end end diff --git a/test/unit/contract_test.rb b/test/unit/contract_test.rb index c3daeae..5d307d5 100644 --- a/test/unit/contract_test.rb +++ b/test/unit/contract_test.rb @@ -247,10 +247,11 @@ class ContractTest < ActiveSupport::TestCase TimeEntry.generate!(:hours => 4, :issue => @issue2, :project => @project, :activity => @non_billable_activity, :user => @manager) + @deliverable_2.fixed_budgets << FixedBudget.spawn(:budget => 200, :markup => '$100', :paid => true) assert_equal 875, @deliverable_1.profit_left - assert_equal 1125, @deliverable_2.profit_left - assert_equal 2000, contract.profit_left + assert_equal 825, @deliverable_2.profit_left + assert_equal 1700, contract.profit_left end end