9 Commits

Author SHA1 Message Date
Eric Davis
30e7142c50 [#6898] Check for project variable before using 2012-05-15 10:45:12 -07:00
Eric Davis
2c2ce0d9f3 Fix syntax error that occurs in jquery 1.7 with :nth-child 2012-01-19 11:36:10 -08:00
Eric Davis
9cacef1299 Only load jquery.js if it isn't being loaded by the app 2012-01-19 11:35:51 -08:00
Eric Davis
d6837b67e7 Fixup i18n strings 2011-12-12 16:01:43 -08:00
Eric Davis
8ecef07c3c [#6714] Remove empty deliverable budget items on submissions 2011-12-12 16:00:57 -08:00
Eric Davis
3f794df99d Moved code to the redmine_overhead plugin 2011-11-14 16:36:21 -08:00
Eric Davis
492435d560 Merge branch 'master' into 6636-deliverable-report 2011-11-14 11:13:19 -08:00
Eric Davis
62c74885b5 [#6680] Round the hours in the summary 2011-11-14 11:10:55 -08:00
Eric Davis
6957c8a114 [#6574] Work around sorting errors on unsaved records
When the deliverable form isn't saved (validation errors) then
the unsaved budgets would cause sorting errors due to nil ids.
2011-11-14 10:20:24 -08:00
11 changed files with 133 additions and 64 deletions

View File

@@ -8,13 +8,13 @@ class DeliverablesController < InheritedResources::Base
helper :contracts
helper :contract_formatter
include ContractsHelper
def index
redirect_to contract_url(@project, @contract)
end
def create
remove_empty_budget_items(params)
@deliverable = begin_of_association_chain.deliverables.build(params[:deliverable])
if params[:deliverable] && params[:deliverable][:type] && Deliverable.valid_types.include?(params[:deliverable][:type])
@deliverable.type = params[:deliverable][:type]
@@ -25,6 +25,7 @@ class DeliverablesController < InheritedResources::Base
def update
@deliverable = begin_of_association_chain.deliverables.find_by_id(params[:id])
params[:deliverable] = params[:fixed_deliverable] || params[:hourly_deliverable] || params[:retainer_deliverable]
remove_empty_budget_items(params)
update!(:notice => l(:text_flash_deliverable_updated, :name => @deliverable.title)) { contract_url(@project, @contract) }
end
@@ -38,16 +39,8 @@ class DeliverablesController < InheritedResources::Base
end
def finances
@deliverable = @contract.deliverables.find(params[:id])
period = extract_period(params[:period])
if period
@period = validate_period(@deliverable, period)
else
@period = nil
end
respond_to do |format|
format.js { render :partial => 'deliverables/finances', :locals => {:contract => @contract, :deliverable => @deliverable, :period => @period } }
format.js { render :partial => 'deliverables/finances', :locals => {:contract => @contract, :deliverable => @contract.deliverables.find(params[:id])} }
format.html { }
end
@@ -84,4 +77,27 @@ class DeliverablesController < InheritedResources::Base
period
end
# Remove empty budgets. Will prevent validation errors
# from empty fields submitted from the bulk adding form.
#
# LSS Clients #6714
def remove_empty_budget_items(params)
params["deliverable"]["labor_budgets_attributes"].reject! {|key, b| budget_item_empty?(b) }
params["deliverable"]["overhead_budgets_attributes"].reject! {|key, b| budget_item_empty?(b) }
params["deliverable"]["fixed_budgets_attributes"].reject! {|key, b| fixed_budget_item_empty?(b) }
end
def budget_item_empty?(item)
(item["time_entry_activity_id"].blank?) &&
(item["hours"].blank? || item["hours"].to_f == 0.0) &&
(item["budget"].blank? || item["budget"].gsub('$','').to_f == 0.0)
end
def fixed_budget_item_empty?(item)
(item["title"].blank?) &&
(item["budget"].blank? || item["budget"].gsub('$','').to_f == 0.0) &&
(item["markup"].blank? || item["markup"].gsub('$','').to_d == 0.0)
end
end

View File

@@ -26,7 +26,7 @@
<%= content_tag(:label, l(:field_labor)) %>
<table id="deliverable-labor" class="deliverable_finance_table">
<tbody>
<% form.fields_for :labor_budgets, labor_budgets.sort_by(&:id) do |labor_budget| %>
<% form.fields_for :labor_budgets, labor_budgets.sort_by {|b| b.id || 0 } do |labor_budget| %>
<%= render :partial => 'labor_budget_form', :locals => {:labor_budget => labor_budget} %>
<% end %>
</tbody>
@@ -37,7 +37,7 @@
<%= content_tag(:label, l(:field_overhead)) %>
<table id="deliverable-overhead" class="deliverable_finance_table">
<tbody>
<% form.fields_for :overhead_budgets, overhead_budgets.sort_by(&:id) do |overhead_budget| %>
<% form.fields_for :overhead_budgets, overhead_budgets.sort_by {|b| b.id || 0 } do |overhead_budget| %>
<%= render :partial => 'overhead_budget_form', :locals => {:overhead_budget => overhead_budget} %>
<% end %>
</tbody>
@@ -48,7 +48,7 @@
<div id="deliverable-fixed" class="fixed-item-form">
<label for="contract_discount">Fixed</label>
<% form.fields_for :fixed_budgets, fixed_budgets.sort_by(&:id) do |fixed_budget| %>
<% form.fields_for :fixed_budgets, fixed_budgets.sort_by {|b| b.id || 0 } do |fixed_budget| %>
<%= render :partial => 'fixed_budget_form', :locals => {:fixed_budget => fixed_budget} %>
<%= wikitoolbar_for "fixed-description#{fixed_budget.object.object_id}" %>
<% end %>

View File

@@ -2,21 +2,11 @@
<%= l(:text_deliverable_spending_summary,
:spent => content_tag(:span, h(number_to_currency(deliverable.labor_budget_spent, :precision => Deliverable::ViewPrecision)), :class => 'spent'),
:total => content_tag(:span, h(number_to_currency(deliverable.labor_budget_total, :precision => Deliverable::ViewPrecision)), :class => 'total'),
:hours => content_tag(:span, h(deliverable.labor_hours_spent_total), :class => 'hours')) %>
:hours => content_tag(:span, h(number_with_precision(deliverable.labor_hours_spent_total, :precision => Deliverable::ViewPrecision)), :class => 'hours')) %>
</div>
<h2><%= h(deliverable.title) %></h2>
<% if deliverable.retainer? %>
<div class="deliverable-period">
<form method="get" action="<%= finances_contract_deliverable_path(deliverable.project, contract, deliverable, :format => 'js') %>">
<select name="period" id="retainer_period_change_<%= h(deliverable.id) %>" class="retainer_period_change">
<%= retainer_period_options(deliverable, :selected => period) %>
</select>
</form>
</div>
<% end %>
<% has_categories = deliverable.project.issue_categories.count > 0 %>
<div id="deliverable-activities" class="deliverable-finance-report" style=" width: 48%">

View File

@@ -1 +1 @@
<%= render :partial => 'finances', :locals => {:contract => @contract, :deliverable => @deliverable, :period => @period } %>
<%= render :partial => 'finances', :locals => {:contract => @contract, :deliverable => @contract.deliverables.find(params[:id])} %>

View File

@@ -1,4 +1,4 @@
<% if project.module_enabled?(:contracts) && User.current.allowed_to?(:assign_deliverable_to_issue, project) %>
<% if project && project.module_enabled?(:contracts) && User.current.allowed_to?(:assign_deliverable_to_issue, project) %>
<p>
<%= label_tag(:deliverable_id, l(:field_deliverable)) %>
<%= select_tag('deliverable_id',

View File

@@ -2,7 +2,7 @@ jQuery(function($) {
$("#ajax-indicator").ajaxStart(function(){ $(this).show().css('z-index', '9999'); });
$("#ajax-indicator").ajaxStop(function(){ $(this).hide(); });
var right_align = $('#contract-terms .finance tr td:nth-child ~ td, .c_overview table.right tr td:nth-child ~ td, #deliverables table tr.click td:nth-child(5) ~ td, .deliverable_finance_table tr.aright td:nth-child ~ td');
var right_align = $('#contract-terms .finance tr td:nth-child(1) ~ td, .c_overview table.right tr td:nth-child(1) ~ td, #deliverables table tr.click td:nth-child(5) ~ td, .deliverable_finance_table tr.aright td:nth-child(1) ~ td');
if (right_align.length > 0) {
right_align.after().css("text-align", "right");

View File

@@ -22,7 +22,7 @@ en:
field_account_executive_short: "Acct. Mgr."
field_end_date: "End Date"
text_new_contract: "New Contract"
text_edit_contract_name: "Edit {{name}}"
text_edit_contract_name: "Edit %{name}"
field_billable_rate: "Billable Rate"
field_billable_rate_hint: "$"
field_discount: "Discount"
@@ -34,7 +34,7 @@ en:
field_details: "Details"
button_add_new: Add New
text_new_deliverable: New Deliverable
text_edit_deliverable_title: "Edit {{title}}"
text_edit_deliverable_title: "Edit %{title}"
field_manager: Manager
field_labor: Labor
field_overhead: Overhead
@@ -43,7 +43,7 @@ en:
field_feature_sign_off: Feature Sign Off
field_warranty_sign_off: Warranty Sign Off
text_deliverable_finances: Deliverable Finances
text_deliverable_finances_date: "Deliverable Finances - {{date}}"
text_deliverable_finances_date: "Deliverable Finances - %{date}"
text_short_hours: hrs
text_dollar_sign: '$'
field_client_point_of_contact: "Point of Contact"
@@ -85,15 +85,15 @@ en:
text_changed_period_message: "The period for this deliverable has been changed. Would you like to expand/shrink the Deliverable Finances?"
field_current_period: "Current period"
text_retainer_monthly_message: "Enter budget for a representative month. Any overrides to individual months can be done via the editor after saving."
text_flash_deliverable_created: "Deliverable: {{name}} was successfully created."
text_flash_deliverable_updated: "Deliverable: {{name}} was successfully updated."
text_flash_deliverable_deleted: "Deliverable: {{name}} was successfully deleted."
text_flash_deliverable_created: "Deliverable: %{name} was successfully created."
text_flash_deliverable_updated: "Deliverable: %{name} was successfully updated."
text_flash_deliverable_deleted: "Deliverable: %{name} was successfully deleted."
field_budget: Budget
field_markup: Markup
field_paid: Paid
field_spent: Spent
field_profit: Profit
text_error_message_orphaned_time: "There is {{amount}} worth of time clocked to issues that are not assigned to any deliverables."
text_error_message_orphaned_time: "There is %{amount} worth of time clocked to issues that are not assigned to any deliverables."
text_error_message_update_orphaned_time: "Please update the orphaned issues."
field_estimated: Estimated
text_deliverable_locked_warning: "This deliverable is locked and cannot be saved without changing it's status to Open."

View File

@@ -6,15 +6,25 @@ module RedmineContracts
context[:controller].is_a?(ContractsController) ||
context[:controller].is_a?(DeliverablesController)
)
return stylesheet_link_tag("redmine_contracts", :plugin => "redmine_contracts", :media => "screen") +
stylesheet_link_tag('smoothness/jquery-ui-1.8.15.custom.css', :plugin => "redmine_contracts") +
tags = [stylesheet_link_tag("redmine_contracts", :plugin => "redmine_contracts", :media => "screen")]
tags << stylesheet_link_tag('smoothness/jquery-ui-1.8.15.custom.css', :plugin => "redmine_contracts")
javascript_include_tag('jquery-1.4.4.min.js', :plugin => 'redmine_contracts') +
javascript_include_tag('jquery.tmpl.min.js', :plugin => 'redmine_contracts') +
javascript_include_tag('jquery-ui-1.8.15.custom.min.js', :plugin => "redmine_contracts") +
javascript_tag('jQuery.noConflict();') +
javascript_include_tag('contracts.js', :plugin => 'redmine_contracts')
jquery_included = begin
ChiliProject::Compatibility && ChiliProject::Compatibility.using_jquery?
rescue NameError
# No compatibilty test
false
end
unless jquery_included
tags << javascript_include_tag('jquery-1.4.4.min.js', :plugin => 'redmine_contracts')
tags << javascript_tag('jQuery.noConflict();')
end
tags << javascript_include_tag('jquery.tmpl.min.js', :plugin => 'redmine_contracts')
tags << javascript_include_tag('jquery-ui-1.8.15.custom.min.js', :plugin => "redmine_contracts")
tags << javascript_include_tag('contracts.js', :plugin => 'redmine_contracts')
return tags.join(' ')
else
return ''
end

View File

@@ -16,27 +16,6 @@ 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

@@ -118,6 +118,34 @@ class DeliverablesEditTest < ActionController::IntegrationTest
assert_equal 1000.0, @overhead_budget.budget
end
should "not create new budget items for the deliverable if the activity, hours, and dollars are not all blank" do
TimeEntryActivity.destroy_all
visit_contract_page(@contract)
click_link_within "#deliverable_details_#{@hourly_deliverable.id}", 'Edit'
assert_response :success
assert_template 'deliverables/edit'
within("#deliverable-labor") do
fill_in "hrs", :with => ''
fill_in "$", :with => '$0'
end
within("#deliverable-overhead") do
fill_in "hrs", :with => '0'
fill_in "$", :with => ''
end
click_button "Save"
assert_response :success
assert_template 'contracts/show'
@hourly_deliverable.reload
assert_equal 0, @hourly_deliverable.labor_budgets.count
assert_equal 0, @hourly_deliverable.overhead_budgets.count
assert_equal 0, @hourly_deliverable.fixed_budgets.count
end
should "show allow editing the Deliverable Finances section for each Retainer period" do
@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)
@@ -476,8 +504,8 @@ class DeliverablesEditTest < ActionController::IntegrationTest
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)
assert_equal 1, @retainer_deliverable.fixed_budgets.count
assert_equal [600], @retainer_deliverable.fixed_budgets.collect(&:budget)
end
context "locked deliverable" do

View File

@@ -278,4 +278,50 @@ class DeliverablesNewTest < ActionController::IntegrationTest
end
should "not create new budget items for the deliverable if the activity, hours, and dollars are all blank" do
@manager = User.generate!
@role = Role.generate!
User.add_to_project(@manager, @project, @role)
TimeEntryActivity.destroy_all
visit_contract_page(@contract)
click_link 'Add New'
assert_response :success
within("#deliverable-details") do
fill_in "Title", :with => 'A New Deliverable with blanks'
select "Hourly", :from => "Type"
select @manager.name, :from => "Manager"
end
within("#deliverable-labor") do
# no activity selected
fill_in "hrs", :with => ''
fill_in "$", :with => '$0'
end
within("#deliverable-overhead") do
# no activity selected
fill_in "hrs", :with => '0'
fill_in "$", :with => ''
end
within("#deliverable-fixed") do
fill_in "title", :with => ''
fill_in "budget", :with => '$0'
fill_in "markup", :with => ''
end
click_button "Save"
assert_response :success
assert_template 'contracts/show'
@deliverable = Deliverable.last
assert_equal "A New Deliverable with blanks", @deliverable.title
assert_equal 0, @deliverable.labor_budgets.count
assert_equal 0, @deliverable.overhead_budgets.count
assert_equal 0, @deliverable.fixed_budgets.count
end
end