Merge branch '6574-budgets-by-activity'

This commit is contained in:
Eric Davis
2011-10-12 10:57:21 -07:00
28 changed files with 359 additions and 79 deletions

View File

@@ -6,7 +6,7 @@ Dir[File.expand_path(File.dirname(__FILE__)) + "/lib/tasks/**/*.rake"].sort.each
RedminePluginSupport::Base.setup do |plugin|
plugin.project_name = 'redmine_contracts'
plugin.default_task = [:test]
plugin.tasks = [:db, :doc, :release, :clean, :test, :stats, :metrics]
plugin.tasks = [:db, :doc, :release, :clean, :test, :stats]
# TODO: gem not getting this automaticly
plugin.redmine_root = File.expand_path(File.dirname(__FILE__) + '/../../../')
end

View File

@@ -11,9 +11,9 @@ class Deliverable < ActiveRecord::Base
has_many :fixed_budgets
has_many :issues, :dependent => :nullify
accepts_nested_attributes_for :labor_budgets
accepts_nested_attributes_for :overhead_budgets
accepts_nested_attributes_for :fixed_budgets
accepts_nested_attributes_for :labor_budgets, :allow_destroy => true
accepts_nested_attributes_for :overhead_budgets, :allow_destroy => true
accepts_nested_attributes_for :fixed_budgets, :allow_destroy => true
# Validations
validates_presence_of :title
@@ -31,7 +31,8 @@ class Deliverable < ActiveRecord::Base
delegate "open?", :to => :contract, :prefix => true, :allow_nil => true
delegate "closed?", :to => :contract, :prefix => true, :allow_nil => true
delegate "locked?", :to => :contract, :prefix => true, :allow_nil => true
delegate :project, :to => :contract, :allow_nil => true
# Callbacks
before_destroy :block_on_locked_contracts
before_destroy :block_on_closed_contracts
@@ -280,6 +281,11 @@ class Deliverable < ActiveRecord::Base
end
end
# Required attribute for AAJ's JournalFormatter
def name
title
end
# Accessors from the budget plugin that need to be wrapped
def subject
warn "[DEPRECATION] Deliverable#subject is deprecated. Please use Deliverable#title instead."

View File

@@ -3,8 +3,10 @@ class LaborBudget < ActiveRecord::Base
# Associations
belongs_to :deliverable
belongs_to :time_entry_activity
# Validations
validates_presence_of :time_entry_activity_id
# Accessors
include DollarizedAttribute

View File

@@ -3,8 +3,10 @@ class OverheadBudget < ActiveRecord::Base
# Associations
belongs_to :deliverable
belongs_to :time_entry_activity
# Validations
validates_presence_of :time_entry_activity_id
# Accessors
include DollarizedAttribute

View File

@@ -121,6 +121,7 @@
<th colspan="2"><%= l(:field_labor) %></th>
<th colspan="2"><%= l(:field_overhead) %></th>
<th colspan="2"><%= l(:field_fixed) %></th>
<th colspan="2"><%= l(:field_total) %></th>
</tr>
</thead>
@@ -135,6 +136,7 @@
<%= 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, deliverable.fixed_budget_total_spent, deliverable.fixed_budget_total, :class => 'fixed') %>
<%= format_budget_for_deliverable(deliverable, deliverable.total_spent, deliverable.total, :class => 'total') %>
<% end %>
<tr id="deliverable_details_<%= h(deliverable.id) %>" class="ign">

View File

@@ -1,6 +1,6 @@
<% validated_period = validate_period(deliverable, period) %>
<td colspan="11" class="deliverable_details_outer_wrapper_<%= h(deliverable.id) %>">
<td colspan="13" class="deliverable_details_outer_wrapper_<%= h(deliverable.id) %>">
<div class="expanded">

View File

@@ -1,3 +1,21 @@
<script type="text/html" id="labor-budget-template">
<% form.fields_for :labor_budgets, resource.labor_budgets.new(:id => 0) do |labor_budget| %>
<%= render :partial => 'labor_budget_form', :locals => {:labor_budget => labor_budget} %>
<% end %>
</script>
<script type="text/html" id="overhead-budget-template">
<% form.fields_for :overhead_budgets, resource.overhead_budgets.new(:id => 0) do |overhead_budget| %>
<%= render :partial => 'overhead_budget_form', :locals => {:overhead_budget => overhead_budget} %>
<% end %>
</script>
<script type="text/html" id="fixed-budget-template">
<% form.fields_for :fixed_budgets, resource.fixed_budgets.new(:id => 0) do |fixed_budget| %>
<%= render :partial => 'fixed_budget_form', :locals => {:fixed_budget => fixed_budget} %>
<% end %>
</script>
<% form.inputs :name => label, :class => "deliverable-finances #{fieldset_class}" do %>
<li style="display:none;" id='retainer-finances-message'>
@@ -7,54 +25,22 @@
<li class="numeric optional">
<%= content_tag(:label, l(:field_labor)) %>
<table id="deliverable-labor" class="deliverable_finance_table">
<% form.fields_for :labor_budgets, labor_budgets do |labor_budget| %>
<%= labor_budget.hidden_field(:year) %>
<%= labor_budget.hidden_field(:month) %>
<tr>
<td>
<%= release(3, "Select field for the Time Entry Activity in a td") %>
</td>
<td>
<p class="inline-hints"><%= labor_budget.label(:hours, l(:text_short_hours)) %></p>
<%= labor_budget.text_field(:hours, :value => format_deliverable_value_fields(labor_budget.object.hours), :class => 'financial') %>
</td>
<td>
<p class="inline-hints"><%= labor_budget.label(:budget, l(:text_dollar_sign)) %></p>
<%= labor_budget.text_field(:budget, :value => format_deliverable_value_fields(labor_budget.object.budget), :class => 'financial') %>
</td>
<td>
<%= release(3, "Green Add button for multiple records") %>
</td>
</tr>
<tbody>
<% form.fields_for :labor_budgets, labor_budgets.sort_by(&:id) do |labor_budget| %>
<%= render :partial => 'labor_budget_form', :locals => {:labor_budget => labor_budget} %>
<% end %>
</tbody>
</table>
</li>
<li class="numeric optional">
<%= content_tag(:label, l(:field_overhead)) %>
<table id="deliverable-overhead" class="deliverable_finance_table">
<% form.fields_for :overhead_budgets, overhead_budgets do |overhead_budget| %>
<%= overhead_budget.hidden_field(:year) %>
<%= overhead_budget.hidden_field(:month) %>
<tr>
<td>
<%= release(3, "Select field for the Time Entry Activity in a td") %>
</td>
<td>
<p class="inline-hints"><%= overhead_budget.label(:hours, l(:text_short_hours)) %></p>
<%= overhead_budget.text_field(:hours, :value => format_deliverable_value_fields(overhead_budget.object.hours),:class => 'financial') %>
</td>
<td>
<p class="inline-hints"><%= overhead_budget.label(:budget, l(:text_dollar_sign)) %></p>
<%= overhead_budget.text_field(:budget, :value => format_deliverable_value_fields(overhead_budget.object.budget), :class => 'financial') %>
</td>
<td>
<%= release(3, "Green Add button for multiple records") %>
</td>
</tr>
<tbody>
<% form.fields_for :overhead_budgets, overhead_budgets.sort_by(&:id) do |overhead_budget| %>
<%= render :partial => 'overhead_budget_form', :locals => {:overhead_budget => overhead_budget} %>
<% end %>
</tbody>
</table>
</li>
@@ -62,34 +48,9 @@
<div id="deliverable-fixed" class="fixed-item-form">
<label for="contract_discount">Fixed</label>
<% form.fields_for :fixed_budgets, fixed_budgets do |fixed_budget| %>
<%= fixed_budget.hidden_field(:year) %>
<%= fixed_budget.hidden_field(:month) %>
<p class="inline-hints"><%= fixed_budget.label(:title, l(:field_title))%>
<%= fixed_budget.text_field(:title) %>
</p>
<p class="inline-hints">
<%= fixed_budget.label(:budget, l(:field_budget))%> <%= l(:text_dollar_sign) %>
<%= fixed_budget.text_field(:budget, :value => format_deliverable_value_fields(fixed_budget.object.budget), :class => 'financial') %>
</p>
<p class="inline-hints">
<%= fixed_budget.label(:markup, l(:field_markup)) %> <%= l(:field_discount_hint) %>
<%= fixed_budget.text_field(:markup, :value => format_deliverable_value_fields_as_dollar_or_percent(fixed_budget.object.markup), :class => 'financial') %>
</p>
<p class="inline-hints">
<%= fixed_budget.label(:paid, l(:field_paid)) %>
<%= fixed_budget.check_box(:paid) %>
</p>
<p class="inline-hints" style="display:none;"><%= fixed_budget.label(:description, l(:field_description), :for => "fixed-description#{fixed_budget.object.object_id}")%></p>
<%= fixed_budget.text_area(:description, :class => 'wiki-edit', :rows => '5', :id => "fixed-description#{fixed_budget.object.object_id}") %>
<% form.fields_for :fixed_budgets, fixed_budgets.sort_by(&:id) do |fixed_budget| %>
<%= render :partial => 'fixed_budget_form', :locals => {:fixed_budget => fixed_budget} %>
<%= wikitoolbar_for "fixed-description#{fixed_budget.object.object_id}" %>
<p><%= release(3, "Green Add button for multiple records") %></p>
<% end %>
</div>

View File

@@ -0,0 +1,33 @@
<div class="fixed-budget-form">
<%= fixed_budget.hidden_field(:id) unless fixed_budget.object.new_record? %>
<%= fixed_budget.hidden_field(:year) %>
<%= fixed_budget.hidden_field(:month) %>
<p class="inline-hints"><%= fixed_budget.label(:title, l(:field_title))%>
<%= fixed_budget.text_field(:title) %>
</p>
<p class="inline-hints">
<%= fixed_budget.label(:budget, l(:field_budget))%> <%= l(:text_dollar_sign) %>
<%= fixed_budget.text_field(:budget, :value => format_deliverable_value_fields(fixed_budget.object.budget), :class => 'financial') %>
</p>
<p class="inline-hints">
<%= fixed_budget.label(:markup, l(:field_markup)) %> <%= l(:field_discount_hint) %>
<%= fixed_budget.text_field(:markup, :value => format_deliverable_value_fields_as_dollar_or_percent(fixed_budget.object.markup), :class => 'financial') %>
</p>
<p class="inline-hints">
<%= fixed_budget.label(:paid, l(:field_paid)) %>
<%= fixed_budget.check_box(:paid) %>
</p>
<p class="inline-hints" style="display:none;"><%= fixed_budget.label(:description, l(:field_description), :for => "fixed-description#{fixed_budget.object.object_id}")%></p>
<%= fixed_budget.text_area(:description, :class => 'wiki-edit', :rows => '5', :id => "fixed-description#{fixed_budget.object.object_id}") %>
<p class="inline-hints add-fixed">
<%= fixed_budget.hidden_field "_destroy", :class=> "delete-flag" %>
<%= link_to_function(l(:button_delete), 'deleteDeliverableFinance(this)', :class => 'delete icon icon-del') %>
<%= link_to_function(l(:button_add), 'addNewDeliverableFixedItem()', :class => 'add icon icon-add', :style => 'display:none;') %>
</p>
</div>

View File

@@ -1,6 +1,7 @@
<%= javascript_tag("var i18nStartDateEmpty = '#{l(:text_start_date_empty)}'") %>
<%= javascript_tag("var i18nEndDateEmpty = '#{l(:text_end_date_empty)}'") %>
<%= javascript_tag("var i18nChangedPeriodMessage = '#{l(:text_changed_period_message)}'") %>
<%= javascript_tag("var i18nAreYouSure = '#{l(:text_are_you_sure)}'") %>
<% if resource.locked? || resource.closed? || resource.contract_locked? || resource.contract_closed? %>
<div class="error_msg">
@@ -56,7 +57,7 @@
<% 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), :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') } %>
<%= render :partial => 'finance_form', :locals => {:resource => resource, :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') %>

View File

@@ -0,0 +1,23 @@
<tr class="labor-budget-form">
<td>
<%= labor_budget.hidden_field(:id) unless labor_budget.object.new_record? %>
<%= labor_budget.hidden_field(:year) %>
<%= labor_budget.hidden_field(:month) %>
<%= labor_budget.label(:time_entry_activity_id, :class => "hidden") %>
<%= labor_budget.select(:time_entry_activity_id, options_from_collection_for_select(@project.billable_activities, :id, :name, labor_budget.object.time_entry_activity_id), {:include_blank => false}, {:class => 'financial'}) %>
</td>
<td>
<p class="inline-hints"><%= labor_budget.label(:hours, l(:text_short_hours)) %></p>
<%= labor_budget.text_field(:hours, :value => format_deliverable_value_fields(labor_budget.object.hours), :class => 'financial') %>
</td>
<td>
<p class="inline-hints"><%= labor_budget.label(:budget, l(:text_dollar_sign)) %></p>
<%= labor_budget.text_field(:budget, :value => format_deliverable_value_fields(labor_budget.object.budget), :class => 'financial') %>
</td>
<td class="add-labor">
<%= labor_budget.hidden_field "_destroy", :class=> "delete-flag" %>
<%= link_to_function(l(:button_delete), 'deleteDeliverableFinance(this)', :class => 'delete icon icon-del') %>
<%= link_to_function(l(:button_add), 'addNewDeliverableLaborItem()', :class => 'add icon icon-add', :style => 'display:none;') %>
</td>
</tr>

View File

@@ -0,0 +1,22 @@
<tr class="overhead-budget-form">
<td>
<%= overhead_budget.hidden_field(:year) %>
<%= overhead_budget.hidden_field(:month) %>
<%= overhead_budget.label(:time_entry_activity_id, :class => "hidden") %>
<%= overhead_budget.select(:time_entry_activity_id, options_from_collection_for_select(@project.non_billable_activities, :id, :name, overhead_budget.object.time_entry_activity_id), {:include_blank => false}, {:class => 'financial'}) %>
</td>
<td>
<p class="inline-hints"><%= overhead_budget.label(:hours, l(:text_short_hours)) %></p>
<%= overhead_budget.text_field(:hours, :value => format_deliverable_value_fields(overhead_budget.object.hours),:class => 'financial') %>
</td>
<td>
<p class="inline-hints"><%= overhead_budget.label(:budget, l(:text_dollar_sign)) %></p>
<%= overhead_budget.text_field(:budget, :value => format_deliverable_value_fields(overhead_budget.object.budget), :class => 'financial') %>
</td>
<td class="add-overhead">
<%= overhead_budget.hidden_field "_destroy", :class=> "delete-flag" %>
<%= link_to_function(l(:button_delete), 'deleteDeliverableFinance(this)', :class => 'delete icon icon-del') %>
<%= link_to_function(l(:button_add), 'addNewDeliverableOverheadItem()', :class => 'add icon icon-add', :style => 'display:none;') %>
</td>
</tr>

View File

@@ -68,6 +68,88 @@ jQuery(function($) {
}
},
showDeliverableAddButtons = function() {
var laborLinks = $('table.deliverable_finance_table .add-labor a.add')
if (laborLinks.length == 0) {
// No link, add a blank form
addNewDeliverableLaborItem();
} else {
laborLinks.hide().last().show();
}
var overheadLinks = $('table.deliverable_finance_table .add-overhead a.add')
if (overheadLinks.length == 0) {
// No link, add a blank form
addNewDeliverableOverheadItem();
} else {
overheadLinks.hide().last().show();
}
var fixedLinks = $('#deliverable-fixed .fixed-budget-form .add-fixed a.add')
if (fixedLinks.length == 0) {
// No link, add a blank form
addNewDeliverableFixedItem();
} else {
fixedLinks.hide().last().show();
}
},
addNewDeliverableLaborItem = function() {
addNewDeliverableFinance('#labor-budget-template',
'#deliverable-labor tbody',
$("tr.labor-budget-form").size(),
'<tr class="labor-budget-form">');
},
addNewDeliverableOverheadItem = function() {
addNewDeliverableFinance('#overhead-budget-template',
'#deliverable-overhead tbody',
$("tr.overhead-budget-form").size(),
'<tr class="overhead-budget-form">');
},
addNewDeliverableFixedItem = function() {
addNewDeliverableFinance('#fixed-budget-template',
'#deliverable-fixed.fixed-item-form',
$("div.fixed-budget-form").size(),
'<div class="fixed-budget-form">');
},
addNewDeliverableFinance = function(templateSelector, appendTemplateTo, countOfExisting, wrapperElement) {
var t = $(templateSelector).tmpl({});
if (t.length > 0) {
var recordLocation = countOfExisting + 1; // increments the Rails [n] placeholder
var newContent = t.html().replace(/\[0\]/g, "[" + recordLocation + "]");
// New ids for textareas for the jsToolBar to attach to
newContent = newContent.replace(/fixed-description\d*/g, "fixed-description" + Math.floor(Math.random() * 100000000))
var newItem = $(wrapperElement).html(newContent)
newItem.appendTo(appendTemplateTo);
newItem.find("textarea.wiki-edit").each(function () {
attachWikiToolbar(this.id);
});
showDeliverableAddButtons();
}
},
// Set the deleted flag for Rails and move it out of the row into
// a hidden table
deleteDeliverableFinance = function(deleteLink) {
if (confirm(i18nAreYouSure)) {
$(deleteLink).parent().find('.delete-flag').val('1')
if ($('#deleted-finances').length == 0) {
$(deleteLink).
closest("form").
append($("<table style='display:none' id='deleted-finances'></table>"));
}
$('#deleted-finances').append(
$(deleteLink). // <a>
parent(). // <td>
parent().hide()
); // <tr>
showDeliverableAddButtons();
}
},
showDeliverableAddButtons();
toggleSpecificDeliverableFields($('form.deliverable'));
$('select#deliverable_type').change(function() {
@@ -125,3 +207,9 @@ jQuery(function($) {
}
})(jQuery);
// Global functions outside of jQuery scoping
function attachWikiToolbar(id) {
var jsToolBarInstance = new jsToolBar($(id));
jsToolBarInstance.draw();
}

1
assets/javascripts/jquery.tmpl.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -26,6 +26,7 @@ html>body .tabular li {overflow:hidden;}
.tabular li.hidden { height: 0; padding: 0; margin: 0; }
/* End tabular */
.hidden { display: none; }
a.contract-delete {color: red; }
.overage { color: #A40000; }
@@ -521,3 +522,5 @@ input.financial{
#edit_contract_1 li#contract_billable_rate_input div{
margin-bottom: 10px;
}
div.fixed-budget-form {padding: 5px 0;}

View File

@@ -100,3 +100,4 @@ en:
text_deliverable_closed_warning: "This deliverable is closed and cannot be saved without changing it's status to Open."
text_contract_locked_warning: "This contract is locked and cannot be saved without changing it's status to Open."
text_contract_closed_warning: "This contract is closed and cannot be saved without changing it's status to Open."
field_time_entry_activity: "Activity"

View File

@@ -0,0 +1,10 @@
class AddTimeEntryActivityIdToLaborBudgets < ActiveRecord::Migration
def self.up
add_column :labor_budgets, :time_entry_activity_id, :integer
add_index :labor_budgets, :time_entry_activity_id
end
def self.down
remove_column :labor_budgets, :time_entry_activity_id
end
end

View File

@@ -0,0 +1,10 @@
class AddTimeEntryActivityIdToOverheadBudgets < ActiveRecord::Migration
def self.up
add_column :overhead_budgets, :time_entry_activity_id, :integer
add_index :overhead_budgets, :time_entry_activity_id
end
def self.down
remove_column :overhead_budgets, :time_entry_activity_id
end
end

View File

@@ -103,7 +103,8 @@ module RedmineContracts
if old_deliverable['total_hours'].present? || old_deliverable['cost_per_hour'].present?
deliverable.labor_budgets << LaborBudget.new(:deliverable => deliverable,
:budget => @total_cost,
:hours => old_deliverable['total_hours'])
:hours => old_deliverable['total_hours'],
:time_entry_activity => first_billable_activity(project))
end
else
@total_cost = 0
@@ -170,7 +171,8 @@ module RedmineContracts
deliverable.overhead_budgets << OverheadBudget.new(:deliverable => deliverable,
:budget => old_deliverable['overhead'],
:hours => hours.to_f.round(2))
:hours => hours.to_f.round(2),
:time_entry_activity => first_non_billable_activity(deliverable.project))
elsif old_deliverable['overhead_percent'].present?
overhead = total * (old_deliverable['overhead_percent'].to_f / 100)
if @overhead_rate != 0
@@ -181,7 +183,8 @@ module RedmineContracts
deliverable.overhead_budgets << OverheadBudget.new(:deliverable => deliverable,
:budget => overhead,
:hours => hours.to_f.round(2))
:hours => hours.to_f.round(2),
:time_entry_activity => first_non_billable_activity(deliverable.project))
end
end
@@ -228,5 +231,13 @@ module RedmineContracts
def self.append_old_deliverable_to_notes(old_deliverable, new_deliverable)
new_deliverable.notes += "Converted data:\n<pre>" + old_deliverable.pretty_inspect + "</pre>"
end
def self.first_billable_activity(project)
project.billable_activities.first || TimeEntryActivity.first
end
def self.first_non_billable_activity(project)
project.non_billable_activities.first || TimeEntryActivity.first
end
end
end

View File

@@ -8,6 +8,11 @@ module RedmineContracts
# * :detail => Detail about the journal change
#
def helper_issues_show_detail_after_setting(context = { })
# This will be skipped in ChiliProject 2.x because
# acts_as_journalized overrides the prop_key with the label
# 'deliverable_id' becomes 'Deliverable' (i18n)
#
# register_on_journal_formatter is used for ChiliProject 2.x support
# TODO Later: Overwritting the caller is bad juju
if context[:detail].prop_key == 'deliverable_id'
context[:detail].reload

View File

@@ -9,6 +9,7 @@ module RedmineContracts
return stylesheet_link_tag("redmine_contracts", :plugin => "redmine_contracts", :media => "screen") +
javascript_include_tag('jquery-1.4.2.min.js', :plugin => 'redmine_contracts') +
javascript_include_tag('jquery.tmpl.min.js', :plugin => 'redmine_contracts') +
javascript_tag('jQuery.noConflict();') +
javascript_include_tag('contracts.js', :plugin => 'redmine_contracts')

View File

@@ -12,6 +12,17 @@ module RedmineContracts
delegate :title, :to => :deliverable, :prefix => true, :allow_nil => true
delegate :contract, :to => :deliverable, :allow_nil => true
# ChiliProject 2.x support for acts_as_journalized.
# Used to format the journal details on the Issue page
#
# See RedmineContracts::Hooks::HelperIssuesShowDetailAfterSettingHook
# for <2.x and Redmine version
#
# TODO: Will not support permissions or custom code in the formatter.
if Issue.respond_to?(:register_on_journal_formatter)
register_on_journal_formatter(:named_association, 'deliverable_id')
end
def contract_name
contract.try(:name)
end

View File

@@ -16,6 +16,27 @@ module RedmineContracts
end
module InstanceMethods
def billable_activities
activities_sorted_by_billable[:billable]
end
def non_billable_activities
activities_sorted_by_billable[:non_billable]
end
private
def activities_sorted_by_billable
split_activities = activities.partition do |activity|
activity.billable?
end
{
:billable => split_activities.first,
:non_billable => split_activities.second
}
end
end
end
end

View File

@@ -261,7 +261,52 @@ class ContractsShowTest < ActionController::IntegrationTest
assert_select "td.fixed.spent-amount", :text => /1,000/
end
end
should "show the total budget for a Deliverable" do
@manager = User.generate!
@deliverable1 = FixedDeliverable.generate!(:contract => @contract, :manager => @manager, :total => '5404')
visit_contract_page(@contract)
assert_select "table#deliverables" do
assert_select "td.total.total-amount", :text => /5,404/
end
end
should "show the total spent for a Deliverable" do
configure_overhead_plugin
@manager = User.generate!
@contract.billable_rate = 200
assert @contract.save
@deliverable1 = HourlyDeliverable.generate!(:contract => @contract, :manager => @manager, :total => '1504')
@issue1 = Issue.generate_for_project!(@project)
@time_entry1 = TimeEntry.generate!(:issue => @issue1,
:project => @project,
:activity => @billable_activity,
:spent_on => Date.today,
:hours => 15,
:user => @manager)
@rate = Rate.generate!(:project => @project,
:user => @manager,
:date_in_effect => Date.yesterday,
:amount => 100)
@deliverable1.issues << @issue1
assert_equal 1, @deliverable1.issues.count
visit_contract_page(@contract)
assert_select "table#deliverables" do
# Using the contract billable rate and not the user rate because it's income, not an expense
assert_select "td.total.spent-amount", :text => /3,000/
end
end
should "show each fixed budget item in the details for the Deliverable" do
@manager = User.generate!

View File

@@ -13,6 +13,7 @@ class DeliverablesEditTest < ActionController::IntegrationTest
@hourly_deliverable = HourlyDeliverable.generate!(:contract => @contract, :manager => @manager, :title => 'An Hourly')
@user = User.generate_user_with_permission_to_manage_budget(:project => @project)
configure_overhead_plugin
login_as(@user.login, 'contracts')
end
@@ -420,10 +421,12 @@ class DeliverablesEditTest < ActionController::IntegrationTest
# * labor hidden month
# * labor hours
# * labor amount
# * labor deleted (hidden)
# * overhead hidden year
# * overhead hidden month
# * overhead hours
# * overhead amount
# * overhead deleted (hidden)
# * fixed hidden year
# * fixed hidden month
# * fixed title
@@ -431,9 +434,10 @@ class DeliverablesEditTest < ActionController::IntegrationTest
# * fixed markup
# * fixed paid checkbox
# * fixed paid hidden field
# * fixed deleted (hidden)
# * total (hidden)
assert_select ".date-2010-01" do
assert_select "input", :count => 16
assert_select "input", :count => 19
assert_select "textarea.wiki-edit", :count => 1 # Fixed description
end

View File

@@ -7,6 +7,7 @@ class DeliverablesNewTest < ActionController::IntegrationTest
@project = Project.generate!(:identifier => 'main')
@contract = Contract.generate!(:project => @project)
@user = User.generate_user_with_permission_to_manage_budget(:project => @project)
configure_overhead_plugin
login_as(@user.login, 'contracts')
end
@@ -231,11 +232,13 @@ class DeliverablesNewTest < ActionController::IntegrationTest
end
within("#deliverable-labor") do
select @billable_activity.name, :from => 'Activity'
fill_in "hrs", :with => '20'
fill_in "$", :with => '$2,000'
end
within("#deliverable-overhead") do
select @non_billable_activity.name, :from => 'Activity'
fill_in "hrs", :with => '10'
fill_in "$", :with => '$1,000'
end
@@ -258,11 +261,13 @@ class DeliverablesNewTest < ActionController::IntegrationTest
@labor_budget = @deliverable.labor_budgets.first
assert_equal 20, @labor_budget.hours
assert_equal 2000.0, @labor_budget.budget
assert_equal @billable_activity, @labor_budget.time_entry_activity
assert_equal 1, @deliverable.overhead_budgets.count
@overhead_budget = @deliverable.overhead_budgets.first
assert_equal 10, @overhead_budget.hours
assert_equal 1000.0, @overhead_budget.budget
assert_equal @non_billable_activity, @overhead_budget.time_entry_activity
assert_equal 1, @deliverable.fixed_budgets.count
@fixed_budget = @deliverable.fixed_budgets.first

View File

@@ -92,6 +92,12 @@ class ActionController::IntegrationTest
end
class ActiveSupport::TestCase
begin
require 'ruby_gc_test_patch'
include RubyGcTestPatch
rescue LoadError
end
def configure_overhead_plugin
@custom_field = TimeEntryActivityCustomField.generate!
Setting['plugin_redmine_overhead'] = {

View File

@@ -2,6 +2,9 @@ require File.dirname(__FILE__) + '/../test_helper'
class LaborBudgetTest < ActiveSupport::TestCase
should_belong_to :deliverable
should_belong_to :time_entry_activity
should_validate_presence_of :time_entry_activity_id
context "#budget=" do
should "strip dollar signs when writing" do

View File

@@ -2,6 +2,9 @@ require File.dirname(__FILE__) + '/../test_helper'
class OverheadBudgetTest < ActiveSupport::TestCase
should_belong_to :deliverable
should_belong_to :time_entry_activity
should_validate_presence_of :time_entry_activity_id
context "#budget=" do
should "strip dollar signs when writing" do