diff --git a/app/helpers/contracts_helper.rb b/app/helpers/contracts_helper.rb
index fcbb441..f9cde35 100644
--- a/app/helpers/contracts_helper.rb
+++ b/app/helpers/contracts_helper.rb
@@ -9,10 +9,16 @@ module ContractsHelper
def format_budget_for_deliverable(deliverable, spent, total, options={})
extra_css_class = options[:class] || ''
-
+
if total > 0 || spent > 0
- content_tag(:td, h(format_value_field_for_contracts(spent)), :class => 'spent-amount ' + extra_css_class) +
- content_tag(:td, h(format_value_field_for_contracts(total)), :class => 'total-amount white ' + extra_css_class)
+ spent_css_classes = 'spent-amount'
+ spent_css_classes << " #{overage_class(spent, total)}"
+ spent_css_classes << ' ' << extra_css_class
+ total_css_classes = 'total-amount white'
+ total_css_classes << ' ' << extra_css_class
+
+ content_tag(:td, h(format_value_field_for_contracts(spent)), :class => spent_css_classes) +
+ content_tag(:td, h(format_value_field_for_contracts(total)), :class => total_css_classes)
else
content_tag(:td, '----', :colspan => '2', :class => 'no-value ' + extra_css_class)
end
@@ -61,12 +67,16 @@ module ContractsHelper
def show_budget_field(object, spent_field, total_field, options={})
formatter = options[:format] || :number_to_currency
- spent_content = send(formatter, object.send(spent_field))
- total_content = send(formatter, object.send(total_field))
+ spent_value = object.send(spent_field)
+ total_value = object.send(total_field)
+ spent_content = send(formatter, spent_value)
+ total_content = send(formatter, total_value)
+ reverse_overage = spent_field.to_s.match(/profit/i)
+
show_field(object, spent_field, options.merge(:raw => true, :wrap_in_td => false)) do
- content_tag(:td, h(spent_content), :class => 'spent') +
+ content_tag(:td, h(spent_content), :class => "spent #{overage_class(spent_value, total_value, :reverse => reverse_overage)}") +
content_tag(:td, h(total_content), :class => 'budget')
end
end
@@ -164,4 +174,27 @@ module ContractsHelper
return '' unless (1..5).include?(version)
image_tag("todo#{version}.png", :plugin => 'redmine_contracts', :title => "Coming in release #{version}. #{message}")
end
+
+ # Overage occurs when spent is negative or spent is greater than budget
+ #
+ # :reverse - spent is reverse, it is overage when it's less than budget
+ def overage?(spent, budget, options={})
+ return false unless spent && budget
+ return true if spent < 0
+
+ if options[:reverse]
+ spent.to_f < budget.to_f
+ else
+ spent.to_f > budget.to_f
+ end
+ end
+
+ def overage_class(spent, budget, options={})
+ if overage?(spent, budget, options)
+ 'overage'
+ else
+ ''
+ end
+ end
+
end
diff --git a/app/views/deliverables/_details_row.html.erb b/app/views/deliverables/_details_row.html.erb
index c10b10d..125f118 100644
--- a/app/views/deliverables/_details_row.html.erb
+++ b/app/views/deliverables/_details_row.html.erb
@@ -52,18 +52,22 @@
| <%= l(:field_labor) %><%= release(3, "Deliverable lightbox") %> |
- <%= h(format_value_field_for_contracts(deliverable.labor_budget_spent(validated_period))) %> |
+
+ <%= h(format_value_field_for_contracts(deliverable.labor_budget_spent(validated_period))) %>
+ |
<%= h(format_value_field_for_contracts(deliverable.labor_budget_total(validated_period))) %> |
- <%= h(format_value_field_for_contracts(deliverable.labor_hours_spent_total(validated_period))) %>/<%= h(format_value_field_for_contracts(deliverable.labor_budget_hours(validated_period))) %> <%= l(:text_short_hours) %>
+ <%= h(format_value_field_for_contracts(deliverable.labor_hours_spent_total(validated_period))) %>/<%= h(format_value_field_for_contracts(deliverable.labor_budget_hours(validated_period))) %> <%= l(:text_short_hours) %>
|
| <%= l(:field_overhead) %><%= release(3, "Deliverable lightbox") %> |
- <%= h(format_value_field_for_contracts(deliverable.overhead_spent(validated_period))) %> |
+
+ <%= h(format_value_field_for_contracts(deliverable.overhead_spent(validated_period))) %>
+ |
<%= h(format_value_field_for_contracts(deliverable.overhead_budget_total(validated_period))) %> |
- <%= h(format_value_field_for_contracts(deliverable.overhead_hours_spent_total(validated_period))) %>/<%= h(format_value_field_for_contracts(deliverable.overhead_budget_hours(validated_period))) %> <%= l(:text_short_hours) %>
+ <%= h(format_value_field_for_contracts(deliverable.overhead_hours_spent_total(validated_period))) %>/<%= h(format_value_field_for_contracts(deliverable.overhead_budget_hours(validated_period))) %> <%= l(:text_short_hours) %>
|
@@ -71,7 +75,9 @@
<% next if fixed_budget.blank_record? %>
| <%= h(fixed_budget.title) %> |
- <%= h(format_value_field_for_contracts(fixed_budget.budget_spent)) %> |
+
+ <%= h(format_value_field_for_contracts(fixed_budget.budget_spent)) %>
+ |
<%= h(format_value_field_for_contracts(fixed_budget.budget)) %> |
|
@@ -80,7 +86,9 @@
<% if show_markup_for?(deliverable, validated_period) %>
| <%= l(:field_markup) %> |
- <%= h(format_value_field_for_contracts(deliverable.fixed_markup_budget_total_spent(validated_period))) %> |
+
+ <%= h(format_value_field_for_contracts(deliverable.fixed_markup_budget_total_spent(validated_period))) %>
+ |
<%= h(format_value_field_for_contracts(deliverable.fixed_markup_budget_total(validated_period))) %> |
|
@@ -88,17 +96,24 @@
| <%= l(:field_profit) %> |
- <%= h(format_value_field_for_contracts(deliverable.profit_left(validated_period))) %> |
- <%= h(format_value_field_for_contracts(deliverable.profit_budget(validated_period))) %> |
+
+ <%= h(format_value_field_for_contracts(deliverable.profit_left(validated_period))) %>
+ |
+ <%= h(format_value_field_for_contracts(deliverable.profit_budget(validated_period))) %> |
|
| <%= l(:field_total) %>: |
- <%= h(format_value_field_for_contracts(deliverable.total_spent(validated_period))) %> |
+
+
+ <%= h(format_value_field_for_contracts(deliverable.total_spent(validated_period))) %>
+
+ |
<%= h(format_value_field_for_contracts(deliverable.total(validated_period))) %> |
- <%= 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) %>
+
+ <%= 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/assets/stylesheets/redmine_contracts.css b/assets/stylesheets/redmine_contracts.css
index fae9acd..4d81f15 100644
--- a/assets/stylesheets/redmine_contracts.css
+++ b/assets/stylesheets/redmine_contracts.css
@@ -27,6 +27,7 @@ html>body .tabular li {overflow:hidden;}
/* End tabular */
a.contract-delete {color: red; }
+.overage { color: #A40000; }
/* Positioning */
diff --git a/test/integration/contracts_show_test.rb b/test/integration/contracts_show_test.rb
index c558712..f39e34f 100644
--- a/test/integration/contracts_show_test.rb
+++ b/test/integration/contracts_show_test.rb
@@ -448,6 +448,54 @@ class ContractsShowTest < ActionController::IntegrationTest
end
end
+ should "show overages in red" do
+ configure_overhead_plugin
+
+ @manager = User.generate!
+
+ @deliverable1 = HourlyDeliverable.generate!(:contract => @contract, :manager => @manager)
+ @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)
+ @deliverable1.issues << @issue1
+ @rate = Rate.generate!(:project => @project,
+ :user => @manager,
+ :date_in_effect => Date.yesterday,
+ :amount => 100)
+
+ assert_equal 1, @deliverable1.issues.count
+
+ visit_contract_page(@contract)
+
+ # Overages on:
+ assert_select '.overage', :count => 14
+ assert_select '.contract-labor .overage', :count => 2
+ assert_select '.contract-overhead .overage', :count => 2
+ assert_select '.contract-profit .overage'
+ assert_select '.contract-estimated-hour.total .overage'
+
+ assert_select '#deliverables .spent-amount.labor.overage'
+ assert_select '#deliverables .spent-amount.overhead.overage'
+ assert_select '#deliverables .labor_budget_spent.overage'
+ assert_select '#deliverables .overhead_budget_spent.overage'
+ assert_select '#deliverables .profit_spent.overage'
+ assert_select '#deliverables .labor_hours .overage'
+ assert_select '#deliverables .overhead_hours .overage'
+ assert_select '#deliverables .total_hours .overage'
+
+ end
+
+
should "show an alert if there is orphaned time or issues" do
configure_overhead_plugin