[#6636] Add an action to show deliverable finances
This commit is contained in:
@@ -36,6 +36,14 @@ class DeliverablesController < InheritedResources::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def finances
|
||||||
|
respond_to do |format|
|
||||||
|
format.js { render :partial => 'deliverables/finances', :locals => {:contract => @contract, :deliverable => @contract.deliverables.find(params[:id])} }
|
||||||
|
format.html { }
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
destroy!(:notice => l(:text_flash_deliverable_deleted, :name => resource.title)) { contract_url(@project, @contract) }
|
destroy!(:notice => l(:text_flash_deliverable_deleted, :name => resource.title)) { contract_url(@project, @contract) }
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -54,7 +54,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="l">
|
<td class="l">
|
||||||
<%= link_to(l(:field_labor), "#", :class => 'deliverable-action-link deliverable-lightbox', "data-deliverable-id" => h(deliverable.id)) %>
|
<%= link_to(l(:field_labor), finances_contract_deliverable_path(@project, contract, deliverable), :class => 'deliverable-action-link deliverable-lightbox', "data-deliverable-id" => h(deliverable.id)) %>
|
||||||
</td>
|
</td>
|
||||||
<td class="labor_budget_spent <%= overage_class(deliverable.labor_budget_spent(validated_period), deliverable.labor_budget_total(validated_period)) %>">
|
<td class="labor_budget_spent <%= overage_class(deliverable.labor_budget_spent(validated_period), deliverable.labor_budget_total(validated_period)) %>">
|
||||||
<%= h(format_value_field_for_contracts(deliverable.labor_budget_spent(validated_period))) %>
|
<%= h(format_value_field_for_contracts(deliverable.labor_budget_spent(validated_period))) %>
|
||||||
@@ -69,7 +69,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="l">
|
<td class="l">
|
||||||
<%= link_to(l(:field_overhead), "#", :class => 'deliverable-action-link deliverable-lightbox', "data-deliverable-id" => h(deliverable.id)) %>
|
<%= link_to(l(:field_overhead), finances_contract_deliverable_path(@project, contract, deliverable), :class => 'deliverable-action-link deliverable-lightbox', "data-deliverable-id" => h(deliverable.id)) %>
|
||||||
</td>
|
</td>
|
||||||
<td class="overhead_budget_spent <%= overage_class(deliverable.overhead_spent(validated_period), deliverable.overhead_budget_total(validated_period)) %>">
|
<td class="overhead_budget_spent <%= overage_class(deliverable.overhead_spent(validated_period), deliverable.overhead_budget_total(validated_period)) %>">
|
||||||
<%= h(format_value_field_for_contracts(deliverable.overhead_spent(validated_period))) %>
|
<%= h(format_value_field_for_contracts(deliverable.overhead_spent(validated_period))) %>
|
||||||
|
|||||||
8
app/views/deliverables/_finances.html.erb
Normal file
8
app/views/deliverables/_finances.html.erb
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<div id="summary" class="contextual">
|
||||||
|
<%= l(:text_deliverable_spending_summary,
|
||||||
|
:spent => content_tag(:span, h(number_to_currency(deliverable.labor_budget_spent, :precision => 0)), :class => 'spent'),
|
||||||
|
:total => content_tag(:span, h(number_to_currency(deliverable.labor_budget_total, :precision => 0)), :class => 'total'),
|
||||||
|
:hours => content_tag(:span, h(deliverable.labor_hours_spent_total), :class => 'hours')) %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2><%= h(deliverable.title) %></h2>
|
||||||
1
app/views/deliverables/finances.html.erb
Normal file
1
app/views/deliverables/finances.html.erb
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<%= render :partial => 'finances', :locals => {:contract => @contract, :deliverable => @contract.deliverables.find(params[:id])} %>
|
||||||
@@ -197,7 +197,8 @@ jQuery(function($) {
|
|||||||
|
|
||||||
$('#dialog-window').
|
$('#dialog-window').
|
||||||
hide().
|
hide().
|
||||||
html('<h2>Hello</h2><p>This is a report for Deliverable #' + deliverableId + '.</p>').
|
html('').
|
||||||
|
load($(this).attr('href') + ".js").
|
||||||
dialog({
|
dialog({
|
||||||
title: "",
|
title: "",
|
||||||
minWidth: 400,
|
minWidth: 400,
|
||||||
|
|||||||
@@ -101,3 +101,4 @@ en:
|
|||||||
text_contract_locked_warning: "This contract is locked 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."
|
text_contract_closed_warning: "This contract is closed and cannot be saved without changing it's status to Open."
|
||||||
field_time_entry_activity: "Activity"
|
field_time_entry_activity: "Activity"
|
||||||
|
text_deliverable_spending_summary: "You've spent %{spent} / %{total} and %{hours} Billable Hours"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
ActionController::Routing::Routes.draw do |map|
|
ActionController::Routing::Routes.draw do |map|
|
||||||
map.resources :contracts, :path_prefix => '/projects/:project_id' do |contracts|
|
map.resources :contracts, :path_prefix => '/projects/:project_id' do |contracts|
|
||||||
contracts.resources :deliverables
|
contracts.resources :deliverables, :member => {:finances => :get}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
2
init.rb
2
init.rb
@@ -17,7 +17,7 @@ Redmine::Plugin.register :redmine_contracts do
|
|||||||
project_module :contracts do
|
project_module :contracts do
|
||||||
permission(:manage_budget, {
|
permission(:manage_budget, {
|
||||||
:contracts => [:index, :new, :create, :show, :edit, :update, :destroy],
|
:contracts => [:index, :new, :create, :show, :edit, :update, :destroy],
|
||||||
:deliverables => [:index, :new, :create, :show, :edit, :update, :destroy]
|
:deliverables => [:index, :new, :create, :show, :edit, :update, :destroy, :finances]
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
77
test/integration/deliverable_finances_test.rb
Normal file
77
test/integration/deliverable_finances_test.rb
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class DeliverableFinancesShowTest < ActionController::IntegrationTest
|
||||||
|
include Redmine::I18n
|
||||||
|
|
||||||
|
def setup
|
||||||
|
configure_overhead_plugin
|
||||||
|
@project = Project.generate!(:identifier => 'main').reload
|
||||||
|
@contract = Contract.generate!(:project => @project, :billable_rate => 10)
|
||||||
|
@manager = User.generate!
|
||||||
|
@deliverable1 = RetainerDeliverable.spawn(:contract => @contract, :manager => @manager, :title => "Retainer Title", :start_date => '2010-01-01', :end_date => '2010-03-31')
|
||||||
|
@deliverable1.labor_budgets << LaborBudget.spawn(:budget => 100, :hours => 10)
|
||||||
|
@deliverable1.overhead_budgets << OverheadBudget.spawn(:budget => 200, :hours => 10)
|
||||||
|
|
||||||
|
@deliverable1.save!
|
||||||
|
@user = User.generate_user_with_permission_to_manage_budget(:project => @project)
|
||||||
|
# 2 hours of $100 billable work
|
||||||
|
@issue1 = Issue.generate_for_project!(@project)
|
||||||
|
@time_entry1 = TimeEntry.generate!(:issue => @issue1,
|
||||||
|
:project => @project,
|
||||||
|
:activity => @billable_activity,
|
||||||
|
:spent_on => Date.today,
|
||||||
|
:hours => 2,
|
||||||
|
:user => @manager)
|
||||||
|
@rate = Rate.generate!(:project => @project,
|
||||||
|
:user => @manager,
|
||||||
|
:date_in_effect => Date.yesterday,
|
||||||
|
:amount => 100)
|
||||||
|
@deliverable1.issues << @issue1
|
||||||
|
|
||||||
|
@user.reload
|
||||||
|
login_as(@user.login, 'contracts')
|
||||||
|
end
|
||||||
|
|
||||||
|
context "for an anonymous request" do
|
||||||
|
should "require login" do
|
||||||
|
logout
|
||||||
|
|
||||||
|
visit "/projects/#{@project.id}/contracts/#{@contract.id}/deliverables/#{@deliverable1.id}/finances"
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'account/login'
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
context "for an unauthorized request" do
|
||||||
|
should "be forbidden" do
|
||||||
|
logout
|
||||||
|
|
||||||
|
@user = User.generate!(:password => 'test', :password_confirmation => 'test')
|
||||||
|
login_as(@user.login, 'test')
|
||||||
|
|
||||||
|
visit "/projects/#{@project.id}/contracts/#{@contract.id}/deliverables/#{@deliverable1.id}/finances"
|
||||||
|
|
||||||
|
assert_response :forbidden
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
context "for an authorized request" do
|
||||||
|
should "render the finance report title section for the deliverable" do
|
||||||
|
visit "/projects/#{@project.id}/contracts/#{@contract.id}/deliverables/#{@deliverable1.id}/finances"
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_select "h2", :text => /#{@deliverable1.title}/
|
||||||
|
|
||||||
|
assert_select "div#summary" do
|
||||||
|
assert_select "span.spent", :text => /\$200/ # $100 * 2
|
||||||
|
assert_select "span.total", :text => /\$300/ # $100 * 3
|
||||||
|
assert_select "span.hours", :text => /2/
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -38,7 +38,7 @@ class RedmineContracts::Hooks::ViewLayoutsBaseHtmlHeadTest < ActionController::T
|
|||||||
|
|
||||||
should "load jquery" do
|
should "load jquery" do
|
||||||
@response.body = hook
|
@response.body = hook
|
||||||
assert_select "script[src*=?]", "jquery-1.4.2.min.js"
|
assert_select "script[src*=?]", "jquery-1.4.4.min.js"
|
||||||
end
|
end
|
||||||
|
|
||||||
should "load the contracts.js JavaScript" do
|
should "load the contracts.js JavaScript" do
|
||||||
@@ -60,7 +60,7 @@ class RedmineContracts::Hooks::ViewLayoutsBaseHtmlHeadTest < ActionController::T
|
|||||||
|
|
||||||
should "load jquery" do
|
should "load jquery" do
|
||||||
@response.body = hook
|
@response.body = hook
|
||||||
assert_select "script[src*=?]", "jquery-1.4.2.min.js"
|
assert_select "script[src*=?]", "jquery-1.4.4.min.js"
|
||||||
end
|
end
|
||||||
|
|
||||||
should "load the contracts.js JavaScript" do
|
should "load the contracts.js JavaScript" do
|
||||||
|
|||||||
Reference in New Issue
Block a user