Compare commits
36
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
61270c60d5 | ||
|
|
cb8fd95f29 | ||
|
|
074d6a47e7 | ||
|
|
de0752ed02 | ||
|
|
ed1d04d18d | ||
|
|
0cb4b1941a | ||
|
|
66f3a07e75 | ||
|
|
4af0860542 | ||
|
|
118b0d7622 | ||
|
|
74795a2788 | ||
|
|
a2dfc1c92b | ||
|
|
67069dc60a | ||
|
|
90d2aeccea | ||
|
|
78c43a8821 | ||
|
|
73e92d2970 | ||
|
|
c652360a6d | ||
|
|
5958285410 | ||
|
|
fcf012c828 | ||
|
|
fe2c058def | ||
|
|
ea00b89af5 | ||
|
|
84c679dc67 | ||
|
|
848616853d | ||
|
|
72aeaac59a | ||
|
|
6ad50c57b2 | ||
|
|
1d644178bd | ||
|
|
389fbf3d13 | ||
|
|
729acf200d | ||
|
|
ad8dec8638 | ||
|
|
39edad3e07 | ||
|
|
76a0573341 | ||
|
|
231066098b | ||
|
|
7209871e87 | ||
|
|
1670fb5a73 | ||
|
|
4100972d46 | ||
|
|
e4ce899cd5 | ||
|
|
c8ede6a05d |
@@ -6,12 +6,14 @@ module ContractsHelper
|
||||
end
|
||||
end
|
||||
|
||||
def format_budget_for_deliverable(deliverable, spent, total)
|
||||
def format_budget_for_deliverable(deliverable, spent, total, options={})
|
||||
extra_css_class = options[:class] || ''
|
||||
|
||||
if total > 0 || spent > 0
|
||||
content_tag(:div, h(number_to_currency(spent, :unit => '')), :class => 'spent-amount') +
|
||||
content_tag(:div, h(number_to_currency(total, :unit => '')), :class => 'total-amount')
|
||||
content_tag(:td, h(number_to_currency(spent, :unit => '')), :class => 'spent-amount ' + extra_css_class) +
|
||||
content_tag(:td, h(number_to_currency(total, :unit => '')), :class => 'total-amount white ' + extra_css_class)
|
||||
else
|
||||
'---'
|
||||
content_tag(:td, '----', :colspan => '2', :class => 'no-value ' + extra_css_class)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -23,10 +25,12 @@ module ContractsHelper
|
||||
# </p>
|
||||
def show_field(object, field, options={}, &block)
|
||||
html_options = options[:html_options] || {}
|
||||
label = content_tag(:span, l(("field_" + field.to_s.gsub(/\_id$/, "")).to_sym) + ": ", :class => 'contract-details-label')
|
||||
label_html_options = options[:label_html_options] || {}
|
||||
label = content_tag(:strong, l(("field_" + field.to_s.gsub(/\_id$/, "")).to_sym) + ": ", :class => 'contract-details-label')
|
||||
|
||||
formatter = options[:format]
|
||||
raw_content = options[:raw] || false
|
||||
wrap_in_td = options[:wrap_in_td] || true
|
||||
|
||||
content = ''
|
||||
|
||||
@@ -39,10 +43,16 @@ module ContractsHelper
|
||||
object.send(field)
|
||||
end
|
||||
end
|
||||
|
||||
if raw_content
|
||||
field_content = content
|
||||
else
|
||||
field_content = h(content)
|
||||
end
|
||||
|
||||
content_tag(:p,
|
||||
label +
|
||||
(raw_content ? content : h(content)),
|
||||
content_tag(:tr,
|
||||
content_tag(:td, label, label_html_options) +
|
||||
(wrap_in_td ? content_tag(:td, field_content) : field_content),
|
||||
html_options)
|
||||
end
|
||||
|
||||
@@ -52,10 +62,10 @@ module ContractsHelper
|
||||
spent_content = send(formatter, object.send(spent_field))
|
||||
total_content = send(formatter, object.send(total_field))
|
||||
|
||||
show_field(object, spent_field, options.merge(:raw => true)) do
|
||||
show_field(object, spent_field, options.merge(:raw => true, :wrap_in_td => false)) do
|
||||
|
||||
content_tag(:span, h(spent_content), :class => 'spent') +
|
||||
content_tag(:span, h(total_content), :class => 'budget')
|
||||
content_tag(:td, h(spent_content), :class => 'spent') +
|
||||
content_tag(:td, h(total_content), :class => 'budget')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -53,6 +53,11 @@ class Deliverable < ActiveRecord::Base
|
||||
issues.inject(0) {|total, issue| total += issue.spent_hours }
|
||||
end
|
||||
|
||||
# Wrapper for the old Budget plugins' API
|
||||
def due
|
||||
end_date
|
||||
end
|
||||
|
||||
if Rails.env.test?
|
||||
generator_for :title, :method => :next_title
|
||||
|
||||
|
||||
@@ -1,24 +1,37 @@
|
||||
<% form.inputs do %>
|
||||
<div class="box tabular">
|
||||
<% form.inputs :name => l(:text_general_legend) do %>
|
||||
<%= form.input :name, :required => true %>
|
||||
<%= form.input :account_executive, :required => true %>
|
||||
<%= form.input :account_executive, :required => true, :collection => @project.users.sort %>
|
||||
<li class="boolean optional">
|
||||
<%= label('contract', 'executed') %>
|
||||
<%= check_box 'contract', 'executed' %>
|
||||
</li>
|
||||
<%= form.input :start_date, :required => true, :as => :string, :input_html => {:size => 10}, :hint => calendar_for('contract_start_date') %>
|
||||
<%= form.input :end_date, :required => true, :as => :string, :input_html => {:size => 10}, :hint => calendar_for('contract_end_date') %>
|
||||
<%= form.input :billable_rate, :input_html => {:size => 20}, :hint => l(:field_billable_rate_hint) %>
|
||||
<%= form.input :discount, :input_html => {:size => 20}, :hint => l(:field_discount_hint) %>
|
||||
<%= form.input :discount_note, :input_html => {:class => 'wiki-edit', :rows => '3'} %>
|
||||
<%= form.input :payment_terms, :as => :select, :collection => resource.payment_terms_for_select %>
|
||||
<%= form.input :client_ap_contact_information, :input_html => {:class => 'wiki-edit', :rows => '3'} %>
|
||||
<%= form.input :po_number %>
|
||||
<%= form.input :client_point_of_contact, :input_html => {:class => 'wiki-edit', :rows => '3'} %>
|
||||
<%= form.input :details, :input_html => {:class => 'wiki-edit'} %>
|
||||
<% end %>
|
||||
|
||||
<% form.inputs :name => l(:text_budget_legend) do %>
|
||||
<%= form.input :billable_rate, :input_html => {:size => 20}, :hint => l(:field_billable_rate_hint) %>
|
||||
<%= form.input :discount, :input_html => {:size => 20}, :hint => l(:field_discount_hint) %>
|
||||
<%= form.input :discount_note, :input_html => {:class => 'wiki-edit', :rows => '5'} %>
|
||||
<% end %>
|
||||
|
||||
<% form.inputs :name => l(:text_account_legend) do %>
|
||||
<%= form.input :payment_terms, :as => :select, :collection => resource.payment_terms_for_select %>
|
||||
<%= form.input :po_number %>
|
||||
<%= form.input :client_ap_contact_information, :input_html => {:class => 'wiki-edit', :rows => '5'} %>
|
||||
<%= form.input :client_point_of_contact, :input_html => {:class => 'wiki-edit', :rows => '5'} %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% form.buttons do %>
|
||||
<%= form.commit_button %>
|
||||
<%= link_to(l(:button_cancel), cancel_path) %>
|
||||
<ol>
|
||||
<li class="commit">
|
||||
<%= submit_tag(l(:text_save_contract)) %>
|
||||
<%= link_to(l(:button_cancel), cancel_path) %>
|
||||
</li>
|
||||
</ol>
|
||||
<% end %>
|
||||
|
||||
<%= wikitoolbar_for 'contract_discount_note' %>
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<div class="title-bar" id="upper-title-bar">
|
||||
<%= content_tag(:h2, h(contract.name)) %>
|
||||
|
||||
<div class="title-bar-actions">
|
||||
<span><a href="#TODO-release-4" class="">Log time (Release 4)</a></span>
|
||||
|
||||
<span class="meta-sep"> | </span>
|
||||
|
||||
<span id="watcher"><a class="icon icon-fav-off" href="#TODO-release-3" onclick="">Watch (Release 3)</a></span>
|
||||
|
||||
<span class="meta-sep"> | </span>
|
||||
|
||||
<span><a href="#TODO">Copy (Release ?)</a></span>
|
||||
<span class="meta-sep"> | </span>
|
||||
|
||||
<div class="update button-large">
|
||||
<%= link_to(l(:button_update), edit_contract_path(@project, contract)) %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<%# TODO: release 3/4, contract messages
|
||||
<div class="error_msg">
|
||||
<p>There is $243 worth of time clocked to issues that are not assigned to any deliverables. <span>Please update the orphaned issues.</span> </p>
|
||||
</div>
|
||||
%>
|
||||
@@ -4,8 +4,9 @@
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= content_tag(:h2, h(resource.name)) %>
|
||||
<%= content_tag(:h2, h(l(:text_edit_contract_name, :name => resource.name))) %>
|
||||
|
||||
<% semantic_form_for resource, :url => contract_path(@project, resource), :html => {:class => 'tabular'} do |form| %>
|
||||
<%= render :partial => 'form', :object => form, :locals => {:cancel_path => contract_path(@project, resource)} %>
|
||||
<% end %>
|
||||
|
||||
|
||||
@@ -1,26 +1,50 @@
|
||||
<% if collection.empty? %>
|
||||
<p class="nodata"><%= l(:label_no_data) %></p>
|
||||
<% else %>
|
||||
<table class="list" cellspacing="0" border="0" cellpadding="0" id="contracts">
|
||||
<thead>
|
||||
<th><%= l(:field_id) %></th>
|
||||
<th><%= l(:field_name) %></th>
|
||||
<%# TODO: Status %>
|
||||
<%# TODO: Type %>
|
||||
<th><%= l(:field_account_executive_short) %></th>
|
||||
<th><%= l(:field_total_budget) %></th>
|
||||
<th><%= l(:field_end_date) %></th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% collection.each do |contract| %>
|
||||
<% content_tag_for(:tr, contract) do %>
|
||||
<td class="id"><%= link_to(h(contract.id), contract_path(@project, contract)) %></td>
|
||||
<td class="name"><%= link_to(h(contract.name), contract_path(@project, contract)) %></td>
|
||||
<td class="account-executive"><%= h contract.account_executive.name %></td>
|
||||
<td class="total-budget"><%= h(number_to_currency(contract.total_budget)) %></td>
|
||||
<td class="end-date"><%= h format_date(contract.end_date) %></td>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% end %>
|
||||
<div id="contract_list">
|
||||
|
||||
<div class="title-bar">
|
||||
|
||||
<div class="contextual">
|
||||
<div class="new-issue button-large">
|
||||
<%= link_to(l(:text_new_contract), new_contract_path) %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Active Contacts</h2>
|
||||
|
||||
</div>
|
||||
|
||||
<% if collection.empty? %>
|
||||
<p class="nodata"><%= l(:label_no_data) %></p>
|
||||
<% else %>
|
||||
<table class="list" cellspacing="0" border="0" cellpadding="0" id="contracts">
|
||||
<thead>
|
||||
<th><%= l(:field_id) %></th>
|
||||
<th><%= l(:field_name) %></th>
|
||||
<%# TODO: Release 5, Status %>
|
||||
<%# TODO: Release 5, Type %>
|
||||
<th><%= l(:field_account_executive_short) %></th>
|
||||
<th><%= l(:field_total_budget) %></th>
|
||||
<th><%= l(:field_end_date) %></th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% collection.each do |contract| %>
|
||||
<% content_tag_for(:tr, contract, :class => cycle('','odd')) do %>
|
||||
<td class="id"><%= link_to(h(contract.id), contract_path(@project, contract)) %></td>
|
||||
<td class="name"><%= link_to(h(contract.name), contract_path(@project, contract)) %></td>
|
||||
<td class="account-executive"><%= h contract.account_executive.name %></td>
|
||||
<td class="total-budget"><%= h(number_to_currency(contract.total_budget)) %></td>
|
||||
<td class="end-date"><%= h format_date(contract.end_date) %></td>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% end %>
|
||||
|
||||
<div class="title-bar">
|
||||
<h2>Inactive Contracts</h2>
|
||||
</div>
|
||||
|
||||
<%# TODO: split contracts by active and inactive %>
|
||||
<p class="nodata"><%= l(:label_no_data) %></p>
|
||||
<p>TODO: Release 5 (Contract Status)</p>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,82 +1,294 @@
|
||||
<%# TODO: Need skinning %>
|
||||
<%= render :partial => 'title', :locals => {:contract => resource} %>
|
||||
|
||||
<% div_for(resource) do %>
|
||||
<%= content_tag(:h2, h(resource.name)) %>
|
||||
|
||||
<%= show_field(resource, :status, :html_options => {:class => 'contract-status'}) %>
|
||||
<%= show_field(resource, :account_executive, :html_options => {:class => 'contract-account-manager'}) %>
|
||||
<%= show_field(resource, :contract_type, :html_options => {:class => 'contract-type'}) %>
|
||||
<%= show_field(resource, :start_date, :format => :format_date, :html_options => {:class => 'contract-start-date'}) %>
|
||||
<%= show_field(resource, :end_date, :format => :format_date, :html_options => {:class => 'contract-end-date'}) %>
|
||||
<%= avatar(resource.account_executive, :size => 40) %>
|
||||
|
||||
<%= show_budget_field(resource, :labor_spent, :labor_budget, :html_options => {:class => 'contract-labor'}) %>
|
||||
<%= show_budget_field(resource, :overhead_spent, :overhead_budget, :html_options => {:class => 'contract-overhead'}) %>
|
||||
<%= show_budget_field(resource, :total_spent, :total_budget, :html_options => {:class => 'contract-total'}) %>
|
||||
|
||||
<div id="contract-terms" style="border: 1px solid #000">
|
||||
<%= show_field(resource, :client_point_of_contact, :format => :textilizable, :raw => true, :html_options => {:class => 'contract-client-point-of-contact'}) %>
|
||||
<%= show_field(resource, :executed, :html_options => {:class => 'contract-executed'}) %>
|
||||
<%= show_field(resource, :discount_note, :format => :textilizable, :raw => true, :html_options => {:class => 'contract-discount-note'}) %>
|
||||
<%= show_field(resource, :payment_terms, :format => :format_payment_terms, :html_options => {:class => 'contract-payment-terms'}) %>
|
||||
<%= show_field(resource, :client_ap_contact_information, :format => :textilizable, :raw => true, :html_options => {:class => 'contract-client-ap-contact-information'}) %>
|
||||
<%= show_field(resource, :po_number, :html_options => {:class => 'contract-po-number'}) %>
|
||||
<%= show_field(resource, :details, :format => :textilizable, :raw => true, :html_options => {:class => 'contract-details'}) %>
|
||||
|
||||
<div id="contract-finances" style="border: 1px solid #000">
|
||||
<%= show_budget_field(resource, :labor_spent, :labor_budget, :html_options => {:class => 'contract-labor'}) %>
|
||||
<div class="c_overview">
|
||||
<table class="left">
|
||||
<%= show_field(resource, :status, :html_options => {:class => 'contract-status'}) %>
|
||||
<%= show_field(resource, :account_executive, :html_options => {:class => 'contract-account-manager'}) %>
|
||||
<%= show_field(resource, :contract_type, :html_options => {:class => 'contract-type'}) %>
|
||||
</table>
|
||||
|
||||
<table class="middle">
|
||||
<%= show_field(resource, :start_date, :format => :format_date, :html_options => {:class => 'contract-start-date'}) %>
|
||||
<%= show_field(resource, :end_date, :format => :format_date, :html_options => {:class => 'contract-end-date'}) %>
|
||||
</table>
|
||||
|
||||
<table class="right">
|
||||
<%= show_budget_field(resource, :labor_spent, :labor_budget, :html_options => {:class => 'contract-labor'}, :label_html_options => {:width => '49%'}) %>
|
||||
<%= show_budget_field(resource, :overhead_spent, :overhead_budget, :html_options => {:class => 'contract-overhead'}) %>
|
||||
<%= show_budget_field(resource, :fixed_spent, :fixed_budget, :html_options => {:class => 'contract-fixed'}) %>
|
||||
<%= show_budget_field(resource, :markup_spent, :markup_budget, :html_options => {:class => 'contract-markup'}) %>
|
||||
<%= show_budget_field(resource, :profit_spent, :profit_budget, :html_options => {:class => 'contract-profit'}) %>
|
||||
<%= show_budget_field(resource, :discount_spent, :discount_budget, :html_options => {:class => 'contract-discount'}) %>
|
||||
<%= show_budget_field(resource, :total_spent, :total_budget, :html_options => {:class => 'contract-total'}) %>
|
||||
</table>
|
||||
|
||||
<div class="clear"></div>
|
||||
|
||||
<a href="#" id="expand_terms" class="expand"><%= l(:text_terms_and_financial_overview) %></a>
|
||||
|
||||
<div id="contract-terms">
|
||||
|
||||
<div class="left">
|
||||
<table class="info">
|
||||
<%= show_field(resource, :client_point_of_contact, :format => :textilizable, :raw => true, :html_options => {:class => 'contract-client-point-of-contact padd'}, :label_html_options => {:width => '25%'}) %>
|
||||
<%= show_field(resource, :executed, :html_options => {:class => 'contract-executed'}) %>
|
||||
<%= show_field(resource, :discount_note, :format => :textilizable, :raw => true, :html_options => {:class => 'contract-discount-note'}) %>
|
||||
<%= show_field(resource, :payment_terms, :format => :format_payment_terms, :html_options => {:class => 'contract-payment-terms'}) %>
|
||||
<%= show_field(resource, :client_ap_contact_information, :format => :textilizable, :raw => true, :html_options => {:class => 'contract-client-ap-contact-information'}) %>
|
||||
<%= show_field(resource, :po_number, :html_options => {:class => 'contract-po-number'}) %>
|
||||
<%= show_field(resource, :details, :format => :textilizable, :raw => true, :html_options => {:class => 'contract-details'}) %>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<%= show_field(resource, :billable_rate, :format => :format_hourly_rate, :html_options => {:class => 'contract-billable-rate'}) %>
|
||||
<%= show_budget_field(resource, :estimated_hour_spent, :estimated_hour_budget, :format => :l_hours, :html_options => {:class => 'contract-estimated-hour'}) %>
|
||||
<table class="finance">
|
||||
<%= show_budget_field(resource, :labor_spent, :labor_budget, :html_options => {:class => 'contract-labor'}, :label_html_options => {:width => '46%'}) %>
|
||||
<%= show_budget_field(resource, :overhead_spent, :overhead_budget, :html_options => {:class => 'contract-overhead'}) %>
|
||||
<%= show_budget_field(resource, :fixed_spent, :fixed_budget, :html_options => {:class => 'contract-fixed'}) %>
|
||||
<%= show_budget_field(resource, :markup_spent, :markup_budget, :html_options => {:class => 'contract-markup'}) %>
|
||||
<%= show_budget_field(resource, :profit_spent, :profit_budget, :html_options => {:class => 'contract-profit'}) %>
|
||||
<%= show_budget_field(resource, :discount_spent, :discount_budget, :html_options => {:class => 'contract-discount'}) %>
|
||||
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
<div class="hr"></div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<%= show_budget_field(resource, :total_spent, :total_budget, :html_options => {:class => 'contract-total'}) %>
|
||||
<%= show_field(resource, :billable_rate, :format => :format_hourly_rate, :html_options => {:class => 'contract-billable-rate total'}) %>
|
||||
|
||||
<%= show_budget_field(resource, :estimated_hour_spent, :estimated_hour_budget, :format => :l_hours, :html_options => {:class => 'contract-estimated-hour total'}) %>
|
||||
|
||||
</table>
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clear"></div>
|
||||
|
||||
<div id="deliverables">
|
||||
|
||||
<%= content_tag(:h3, l(:field_deliverable_plural)) %>
|
||||
|
||||
<div class="actions">
|
||||
<a href="#TODO-release-2">CSV (Release 2)</a>
|
||||
<a href="#TODO-release?">View All (9) (Release ?)</a>
|
||||
<%= link_to(l(:button_add_new), new_contract_deliverable_path(@project, resource), :id => 'new-deliverable') %>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="clear"></div>
|
||||
|
||||
<%= link_to(l(:button_update), edit_contract_path(@project, resource)) %>
|
||||
<% if resource.deliverables.empty? %>
|
||||
<p class="nodata"><%= l(:label_no_data) %></p>
|
||||
<% else %>
|
||||
<table width="100%" class="texpand" id="deliverables">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= l(:field_end_date) %></th>
|
||||
<th> </th>
|
||||
<th><%= l(:field_title) %></th>
|
||||
<th><%= l(:field_status) %></th>
|
||||
<th><%= l(:field_manager) %></th>
|
||||
<th colspan="2"><%= l(:field_labor) %></th>
|
||||
<th colspan="2"><%= l(:field_overhead) %></th>
|
||||
<th colspan="2"><%= l(:field_fixed) %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<%= link_to(l(:button_add_new), new_contract_deliverable_path(@project, resource), :id => 'new-deliverable') %>
|
||||
<tbody>
|
||||
<% resource.deliverables.each do |deliverable| %>
|
||||
<% content_tag_for(:tr, deliverable, :class => 'click ' + cycle('even','')) do %>
|
||||
<td width="10%" class="arrow end-date"><span><%= h format_date(deliverable.end_date) %></span></td>
|
||||
<td width="2%" class="type"><%= h deliverable.short_type %></td>
|
||||
<td width="25%" class="title"><%= h deliverable.title %></td>
|
||||
<td width="15%">TODO: Release 5</td>
|
||||
<td width="15%" class="manager"><%= h deliverable.manager.try(:name) %></td>
|
||||
<%= 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 %>
|
||||
<% end %>
|
||||
|
||||
<% if resource.deliverables.empty? %>
|
||||
<p class="nodata"><%= l(:label_no_data) %></p>
|
||||
<% else %>
|
||||
<table class="list" cellspacing="0" border="0" cellpadding="0" id="deliverables">
|
||||
<thead>
|
||||
<th><%= l(:field_end_date) %></th>
|
||||
<th> </th>
|
||||
<th><%= l(:field_title) %></th>
|
||||
<%# TODO: Status %>
|
||||
<th><%= l(:field_manager) %></th>
|
||||
<th><%= l(:field_labor) %></th>
|
||||
<th><%= l(:field_overhead) %></th>
|
||||
<th><%= l(:field_fixed) %></th>
|
||||
<th><%= l(:button_edit) %></th>
|
||||
<th><%= l(:button_delete) %></th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% resource.deliverables.each do |deliverable| %>
|
||||
<% content_tag_for(:tr, deliverable) do %>
|
||||
<td class="end-date"><%= h format_date(deliverable.end_date) %></td>
|
||||
<td class="type"><%= h deliverable.short_type %></td>
|
||||
<td class="title"><%= h deliverable.title %></td>
|
||||
<%# TODO: Status %>
|
||||
<td class="manager"><%= h deliverable.manager.try(:name) %></td>
|
||||
<td class="labor">
|
||||
<%= format_budget_for_deliverable(deliverable, deliverable.labor_budget_spent, deliverable.labor_budget_total) %>
|
||||
</td>
|
||||
<td class="overhead">
|
||||
<%= format_budget_for_deliverable(deliverable, deliverable.overhead_spent, deliverable.overhead_budget_total) %>
|
||||
</td>
|
||||
<td class="fixed">---</td>
|
||||
<td><%= link_to(l(:button_edit), edit_contract_deliverable_path(@project, resource, deliverable), :class => 'icon icon-edit') %></td>
|
||||
<td><%= link_to(l(:button_delete), contract_deliverable_path(@project, resource, deliverable), :method => :delete, :confirm => l(:text_are_you_sure), :class => 'icon icon-del') %></td>
|
||||
<tr id="deliverable_details_<%= h(deliverable.id) %>" class="ign">
|
||||
<td colspan="11">
|
||||
|
||||
<div class="expanded">
|
||||
<div class="info">
|
||||
<div class="title">
|
||||
<%= link_to(l(:button_edit), edit_contract_deliverable_path(@project, resource, deliverable), :class => 'icon icon-edit') %>
|
||||
<%= link_to(l(:button_delete), contract_deliverable_path(@project, resource, deliverable), :method => :delete, :confirm => l(:text_are_you_sure), :class => 'icon icon-del') %>
|
||||
</div>
|
||||
|
||||
<%= textilizable(deliverable, :notes) %>
|
||||
|
||||
<table>
|
||||
<%= show_field(deliverable, :start_date, :format => :format_date, :html_options => {:class => 'deliverable-start-date'}) %>
|
||||
<%= show_field(deliverable, :end_date, :format => :format_date, :html_options => {:class => 'deliverable-end-date'}) %>
|
||||
</table>
|
||||
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<%# TODO: Release 2, skinning port %>
|
||||
<div class="finance">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th> </th>
|
||||
<th>Spent</th>
|
||||
<th>Budget</th>
|
||||
<th>Hours</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr class="fill">
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="l"><a href="#"><strong>Labor</strong></a></td>
|
||||
<td><%= h(deliverable.labor_budget_spent) %></td>
|
||||
<td><%= h(deliverable.labor_budget_total) %></td>
|
||||
<td> TODO: Release 2 / TODO hrs </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="l"><a href="#"><strong>Overhead</strong></a></td>
|
||||
<td><%= h(deliverable.overhead_spent) %></td>
|
||||
<td><%= h(deliverable.overhead_budget_total) %></td>
|
||||
<td> TODO: Release 2 / TODO hrs </td>
|
||||
</tr>
|
||||
<%# TODO: Release 2, Fixed %>
|
||||
<%# TODO: Release 2, Markup %>
|
||||
<tr>
|
||||
<td class="l">Profit</td>
|
||||
<td><%= h(deliverable.profit_left) %></td>
|
||||
<td><%= h(deliverable.profit_budget) %></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="total">
|
||||
<td class="l"><strong>Total:</strong></td>
|
||||
<td><strong><%= h(deliverable.total_spent) %></strong></td>
|
||||
<td><strong><%= h(deliverable.total) %></strong></td>
|
||||
<td><strong>TODO: Release 2</strong></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="issue_status">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2"><%= l(:label_issue_status_plural) %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<%# TODO: Release 2 Issue status counters
|
||||
<tr>
|
||||
<td>Proposed</td>
|
||||
<td class="number">1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>On Hold</td>
|
||||
<td class="number">1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Complete</td>
|
||||
<td class="number">14</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>All</strong></td>
|
||||
<td class="number">16</td>
|
||||
</tr>
|
||||
%>
|
||||
</table>
|
||||
</div>
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% end %>
|
||||
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
|
||||
<% end %> <%# div_for(resource) %>
|
||||
<p>TODO: Release 4, Milestones</p>
|
||||
<!--
|
||||
<div id="milestones">
|
||||
|
||||
<h3>Milestones</h3>
|
||||
<div class="options">
|
||||
<input type="checkbox" checked="checked" /> Event
|
||||
<input type="checkbox" checked="checked" /> Financial
|
||||
<input type="checkbox" checked="checked" /> Dependency
|
||||
</div>
|
||||
<div class="actions">
|
||||
<a href="#">iCal</a>
|
||||
<a href="#">View All (37)</a>
|
||||
<a href="#" id="new-deliverable">Add New</a>
|
||||
</div>
|
||||
<div class="clear"></div>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="c">Done</th>
|
||||
<th>Date</th>
|
||||
<th>Title</th>
|
||||
<th>Status</th>
|
||||
<th>Type</th>
|
||||
<th>Alert</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="odd">
|
||||
<td class="c"><input type="checkbox" value="1" /></td>
|
||||
<td>11/19/2009</td>
|
||||
<td>ACME delivers branding guide</td>
|
||||
<td><span class="red"><strong>Overdue</strong></span></td>
|
||||
<td>Dependency</td>
|
||||
<td>1 day</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td class="c"><input type="checkbox" value="1" /></td>
|
||||
<td>12/01/2009</td>
|
||||
<td>Send Invoice #2</td>
|
||||
<td><span class="red"><strong>Overdue</strong></span></td>
|
||||
<td>Financial</td>
|
||||
<td>EoD</td>
|
||||
</tr>
|
||||
<tr class="odd highlight">
|
||||
<td class="c"><input type="checkbox" value="1" /></td>
|
||||
<td>12/11/2009</td>
|
||||
<td>QA Signoff on 1.2</td>
|
||||
<td>Pending</td>
|
||||
<td>Event</td>
|
||||
<td>3 days</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td class="c"><input type="checkbox" value="1" /></td>
|
||||
<td>12/15/2009</td>
|
||||
<td>Release 1.2</td>
|
||||
<td>Pending</td>
|
||||
<td>Event</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td class="c"><input type="checkbox" value="1" /></td>
|
||||
<td>12/15/2009</td>
|
||||
<td>Deliverable: Load and Release Software</td>
|
||||
<td>Pending</td>
|
||||
<td>Event</td>
|
||||
<td>BoD</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
-->
|
||||
|
||||
<p>TODO: Release 2+, history</p>
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
<% form.inputs do %>
|
||||
<div class="box tabular">
|
||||
<% form.inputs :name => l(:text_deliverable_details_legend) do %>
|
||||
<%= form.input :title, :required => true %>
|
||||
<% if resource.new_record? %>
|
||||
<%= form.input(:type, :required => true, :as => :select, :collection => [["Fixed", "FixedDeliverable"],["Hourly", "HourlyDeliverable"]], :include_blank => false, :input_html => {:class => 'type'}) %>
|
||||
<% else %>
|
||||
<%= form.input :type, :as => :hidden, :class => 'type' %>
|
||||
<% end %>
|
||||
<%= form.input :manager, :required => true, :collection => @project.users %>
|
||||
<%= form.input :manager, :required => true, :collection => @project.users.sort %>
|
||||
<%= form.input :start_date, :as => :string, :input_html => {:size => 10}, :hint => calendar_for('deliverable_start_date') %>
|
||||
<%= form.input :end_date, :as => :string, :input_html => {:size => 10}, :hint => calendar_for('deliverable_end_date') %>
|
||||
<%= form.input :notes, :input_html => {:class => 'wiki-edit', :rows => '5'} %>
|
||||
@@ -20,30 +21,77 @@
|
||||
<%= check_box resource.class.to_s.underscore, 'warranty_sign_off' %>
|
||||
</li>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<%= form.input :total, :input_html => {:size => 10}, :wrapper_html => {:class => 'deliverable_total_input'} %>
|
||||
<% form.inputs :name => l(:text_deliverable_finances), :id => 'deliverable-finances' do %>
|
||||
|
||||
<% form.inputs :name => l(:text_deliverable_finances), :id => 'deliverable-finances' do %>
|
||||
<% form.semantic_fields_for :labor_budgets do |labor_budget| %>
|
||||
<% labor_budget.inputs :name => l(:field_labor), :id => 'deliverable-labor' do %>
|
||||
<%= labor_budget.input :hours, :label => l(:text_short_hours), :input_html => {:size => 10} %>
|
||||
<%= labor_budget.input :budget, :label => l(:text_dollar_sign), :input_html => {:size => 10} %>
|
||||
<li class="numeric optional">
|
||||
<%= content_tag(:label, l(:field_labor)) %>
|
||||
<table id="deliverable-labor" class="deliverable_finance_table">
|
||||
|
||||
<% form.fields_for :labor_budgets do |labor_budget| %>
|
||||
<tr>
|
||||
<%# TODO: Select field for the Time Entry Activity in a td %>
|
||||
<td>
|
||||
<select><option>TODO: Release 3</option></select>
|
||||
</td>
|
||||
<td>
|
||||
<p class="inline-hints"><%= labor_budget.label(:hours, l(:text_short_hours)) %></p>
|
||||
<%= labor_budget.text_field(:hours, :size => 10) %>
|
||||
</td>
|
||||
<td>
|
||||
<p class="inline-hints"><%= labor_budget.label(:budget, l(:text_dollar_sign)) %></p>
|
||||
<%= labor_budget.text_field(:budget, :size => 10) %>
|
||||
</td>
|
||||
<%# TODO: Green Add button for multiple records %>
|
||||
<td>
|
||||
Todo: Add button (Release 3)
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</table>
|
||||
</li>
|
||||
|
||||
<% form.semantic_fields_for :overhead_budgets do |overhead_budget| %>
|
||||
<% overhead_budget.inputs :name => l(:field_overhead), :id => 'deliverable-overhead' do %>
|
||||
<%= overhead_budget.input :hours, :label => l(:text_short_hours), :input_html => {:size => 10} %>
|
||||
<%= overhead_budget.input :budget, :label => l(:text_dollar_sign), :input_html => {:size => 10} %>
|
||||
<li class="numeric optional">
|
||||
<%= content_tag(:label, l(:field_overhead)) %>
|
||||
<table id="deliverable-overhead" class="deliverable_finance_table">
|
||||
|
||||
<% form.fields_for :overhead_budgets do |overhead_budget| %>
|
||||
<tr>
|
||||
<%# TODO: Select field for the Time Entry Activity in a td %>
|
||||
<td>
|
||||
<select><option>TODO: Release 3</option></select>
|
||||
</td>
|
||||
<td>
|
||||
<p class="inline-hints"><%= overhead_budget.label(:hours, l(:text_short_hours)) %></p>
|
||||
<%= overhead_budget.text_field(:hours, :size => 10) %>
|
||||
</td>
|
||||
<td>
|
||||
<p class="inline-hints"><%= overhead_budget.label(:budget, l(:text_dollar_sign)) %></p>
|
||||
<%= overhead_budget.text_field(:budget, :size => 10) %>
|
||||
</td>
|
||||
<%# TODO: Green Add button for multiple records %>
|
||||
<td>
|
||||
Todo: Add button (Release 3)
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</table>
|
||||
</li>
|
||||
|
||||
<%= form.input :total, :input_html => {:size => 10}, :wrapper_html => {:class => 'deliverable_total_input'}, :hint => l(:text_dollar_sign) %>
|
||||
|
||||
<% end %>
|
||||
|
||||
</div>
|
||||
|
||||
<% form.buttons do %>
|
||||
<%= form.commit_button :label => l(:button_save) %>
|
||||
<%= link_to(l(:button_cancel), cancel_path) %>
|
||||
<ol>
|
||||
<li class="commit">
|
||||
<%= submit_tag(l(:button_save)) %>
|
||||
<%= link_to(l(:button_cancel), cancel_path) %>
|
||||
</li>
|
||||
</ol>
|
||||
<% end %>
|
||||
|
||||
<%= wikitoolbar_for resource.to_underscore + '_notes' %>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<%= content_tag(:h2, h(resource.title)) %>
|
||||
<%= render :partial => 'contracts/title', :locals => {:contract => @contract} %>
|
||||
|
||||
<%= content_tag(:h2, h(l(:text_edit_deliverable_title, :title => resource.title))) %>
|
||||
|
||||
<% semantic_form_for [@project, @contract, setup_nested_deliverable_records(resource)], :url => contract_deliverable_path(@project, @contract, resource), :html => {:class => 'deliverable tabular'} do |form| %>
|
||||
<%= render :partial => 'form', :object => form, :locals => {:cancel_path => contract_path(@project, @contract)} %>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<%= render :partial => 'contracts/title', :locals => {:contract => @contract} %>
|
||||
|
||||
<%= content_tag(:h2, l(:text_new_deliverable)) %>
|
||||
|
||||
<% semantic_form_for [@project, @contract, setup_nested_deliverable_records(resource)], :url => contract_deliverables_path(@project, @contract), :html => {:class => 'deliverable tabular'} do |form| %>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<% if project.module_enabled?(:contracts) %>
|
||||
<p>
|
||||
<%= label_tag(:deliverable_id, l(:field_deliverable)) %>
|
||||
<% options = project.contracts.inject([]) {|data, contract|
|
||||
data << [contract.name, contract.deliverables.collect {|d| [d.title, d.id]} ]
|
||||
} %>
|
||||
|
||||
<%= select_tag('deliverable_id',
|
||||
content_tag('option', l(:label_no_change_option), :value => '') +
|
||||
content_tag('option', l(:label_none), :value => 'none') +
|
||||
grouped_options_for_select(options)) %>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<% if project.module_enabled?(:contracts) %>
|
||||
<p>
|
||||
<% options = project.contracts.inject([]) {|data, contract|
|
||||
data << [contract.name, contract.deliverables.collect {|d| [d.title, d.id]} ]
|
||||
} %>
|
||||
<%= form.select(:deliverable_id, grouped_options_for_select(options, issue.deliverable_id), {:include_blank => true}) %>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<% if project.module_enabled?(:contracts) %>
|
||||
<tr>
|
||||
<th class="deliverable"><%= l(:field_deliverable) %>:</th>
|
||||
<td class="deliverable"><%= h(issue.deliverable.title) if issue.deliverable.present? %></td>"
|
||||
</tr>
|
||||
<% end %>
|
||||
|
||||
@@ -1,4 +1,27 @@
|
||||
jQuery(function($) {
|
||||
|
||||
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');
|
||||
|
||||
if (right_align.length > 0) {
|
||||
right_align.after().css("text-align", "right");
|
||||
}
|
||||
|
||||
$("#deliverables table tbody tr td:contains('---')").css("text-align", "center");
|
||||
|
||||
|
||||
$(".texpand").jExpand();
|
||||
|
||||
$(".texpand").find("tr.even").next('tr:first').addClass("even");
|
||||
|
||||
$(window).resize(function() {
|
||||
|
||||
});
|
||||
|
||||
$('#expand_terms').click( function(){
|
||||
$(this).next().slideToggle();
|
||||
$(this).toggleClass('alt');
|
||||
});
|
||||
|
||||
toggleSpecificDeliverableFields = function(form) {
|
||||
var deliverableType = form.find('.type').val();
|
||||
|
||||
@@ -17,3 +40,26 @@ jQuery(function($) {
|
||||
toggleSpecificDeliverableFields($('form.deliverable'));
|
||||
});
|
||||
});
|
||||
|
||||
/* Jquery Table Expander Plugin */
|
||||
(function($){
|
||||
$.fn.jExpand = function(){
|
||||
var element = this;
|
||||
$(element).find("tr.ign").hide();
|
||||
|
||||
$(element).find("tr.click").click(function() {
|
||||
$(this).toggleClass("noborder");
|
||||
$(this).next("tr").toggle();
|
||||
$(this).find('.arrow').toggleClass("alt");
|
||||
|
||||
var box_height = $(this).next().find('.expanded').height();
|
||||
var table_height = $(this).next().find('.finance table').height();
|
||||
|
||||
if(box_height-table_height > 0){
|
||||
$(this).next().find('.finance table .fill td').css("padding-top", box_height-table_height+2);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
})(jQuery);
|
||||
|
||||
@@ -12,6 +12,14 @@ html>body .tabular li {overflow:hidden;}
|
||||
|
||||
.tabular .inline-hints { color:#666; margin:0.5em 0 0 0; padding: 0px; display: inline; }
|
||||
|
||||
.deliverable_finance_table .inline-hints {
|
||||
padding-top:4px;
|
||||
}
|
||||
|
||||
.no-value {
|
||||
text-align:center;
|
||||
color:#999;
|
||||
}
|
||||
.tabular li.required label { color: #484848; }
|
||||
.tabular li.required label span.required {color: #bb0000;}
|
||||
|
||||
@@ -21,11 +29,477 @@ html>body .tabular li {overflow:hidden;}
|
||||
a.contract-delete {color: red; }
|
||||
|
||||
/* Positioning */
|
||||
#deliverable-finances ol li { display: inline; }
|
||||
#deliverable-finances ol li label { float: none; margin-left: 0; }
|
||||
|
||||
#deliverables td.labor, #deliverables td.overhead, #deliverables td.fixed { text-align: center; }
|
||||
#deliverables td.labor div, #deliverables td.overhead div, #deliverables td.fixed div { text-align: right; display: inline; padding: 0 5px; width: 50%; }
|
||||
.spent, .budget { text-align: right; padding: 0 5px; }
|
||||
|
||||
span.contract-details-label { font-weight: bold; }
|
||||
|
||||
/* Design */
|
||||
.tabular li{
|
||||
padding-left: 120px; /*width of left column containing the label elements*/
|
||||
}
|
||||
|
||||
.tabular li.commit {
|
||||
padding-left: 0px; /* Don't pad submit buttons */
|
||||
}
|
||||
|
||||
#content .error_msg{
|
||||
background: #ffd5d5;
|
||||
color: #a40000;
|
||||
border: 1px solid #a40000;
|
||||
margin: 5px 0 10px 0;
|
||||
}
|
||||
|
||||
#content .error_msg p{
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
#content .error_msg p span{
|
||||
font-weight: bold;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.contract .gravatar{
|
||||
float: left;
|
||||
border: 1px solid #b4d1d9;
|
||||
padding: 0;
|
||||
margin-top: 10px;
|
||||
margin-left: 6px;
|
||||
margin-right: 25px;
|
||||
|
||||
}
|
||||
|
||||
#content .contract .fixed-item,
|
||||
#content .contract .fixed-item-form {
|
||||
border-top: 1px dotted #999;
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
#content .contract .fixed-items {
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 1px dotted #999;
|
||||
}
|
||||
|
||||
.add_fixed a{
|
||||
display: block;
|
||||
margin: 15px 0 15px 0;
|
||||
color: #2A5685;
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
.select_dropdown{
|
||||
width: 190px;
|
||||
}
|
||||
|
||||
#content .contract table td,
|
||||
#content .contract table th{
|
||||
padding: 2px 5px 2px 5px;
|
||||
}
|
||||
|
||||
#deliverable-overhead ol li,
|
||||
#deliverable-labor ol li{
|
||||
padding-left: 155px
|
||||
}
|
||||
|
||||
#content table.deliverable_finance_table{
|
||||
width: 600px;
|
||||
}
|
||||
|
||||
#content table.deliverable_finance_table select{
|
||||
width: 145px;
|
||||
}
|
||||
|
||||
#content table.deliverable_finance_table input{
|
||||
text-align: right;
|
||||
width: 65px;
|
||||
}
|
||||
|
||||
#content table.deliverable_finance_table,
|
||||
#content table.deliverable_finance_table tr,
|
||||
#content table.deliverable_finance_table tr td{
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.deliverable_finance_table p.inline-hints label {font-weight: normal; float: none; display: auto; margin-left: 0px; } /* An inline label so it needs to be reset from .tabular */
|
||||
|
||||
#expand_terms{
|
||||
margin: 10px 0 10px 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#content #contract_list table{
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#content #contract_list table tbody tr td.name a{
|
||||
color: #2f8fa5;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#content #contract_list table tbody tr td.name a:hover{
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#content #contract_list table tbody tr td.priority_1{
|
||||
background: #ffaaaa;
|
||||
}
|
||||
|
||||
#content .c_overview{
|
||||
background: #edf6fa;
|
||||
border: 1px solid #dcebf0;
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
padding: 6px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#content .c_overview table{
|
||||
width: 230px;
|
||||
float: left;
|
||||
border: 0;
|
||||
}
|
||||
#content .c_overview table.left{
|
||||
float:left;
|
||||
width:30%;
|
||||
}
|
||||
|
||||
#content .c_overview table.middle{
|
||||
margin-right:3%;
|
||||
margin-left:3%;
|
||||
width:auto;
|
||||
}
|
||||
|
||||
#content .c_overview table.right{
|
||||
width:30%;
|
||||
max-width:300px;
|
||||
float:right;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#content .c_overview table td{
|
||||
border: 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#content .c_overview table tr:hover td,
|
||||
#content .c_overview table tr:hover,
|
||||
#content .c_overview table td:hover{
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
#content .c_overview a.expand{
|
||||
background: url(../../../images/arrow_collapsed.png) no-repeat;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
#content .c_overview a.expand.alt{
|
||||
background: url(../../../images/arrow_expanded.png) no-repeat;
|
||||
}
|
||||
|
||||
#deliverables .arrow{
|
||||
background: url(../../../images/arrow_collapsed.png) no-repeat;
|
||||
background-position: 0 6px;
|
||||
|
||||
}
|
||||
#deliverables .arrow.alt{
|
||||
background: url(../../../images/arrow_expanded.png) no-repeat;
|
||||
background-position: 0 6px;
|
||||
}
|
||||
|
||||
#deliverables .arrow span{
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
#contract-terms,
|
||||
.deliverable_overview{
|
||||
background: #f6fbfd;
|
||||
border: 1px solid #d5dde1;
|
||||
-moz-border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#contract-terms table .hr{
|
||||
border-top: 1px solid #dee0e1;
|
||||
}
|
||||
|
||||
#content #contract-terms table tr.padd td{
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
#contract-terms table.info{
|
||||
width: 60%;
|
||||
background: #f6fbfd;
|
||||
}
|
||||
|
||||
#contract-terms table.finance{
|
||||
width: 30%;
|
||||
max-width:300px;
|
||||
border-left: 1px solid #bed3dd;
|
||||
float: right;
|
||||
margin: 0;
|
||||
background: #fafdfe;
|
||||
}
|
||||
|
||||
#contract-terms table.info td,
|
||||
#contract-terms table.finance td{
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#contract-terms table tr.grey td,
|
||||
#content .contract .grey{
|
||||
color: #808080;
|
||||
}
|
||||
|
||||
#contract-terms span.red,
|
||||
#deliverables span.red,
|
||||
#milestones span.red{
|
||||
color: #990000;
|
||||
}
|
||||
|
||||
#deliverables h3,
|
||||
#milestones h3,
|
||||
#content #history h3{
|
||||
float: left;
|
||||
font-size: 22px;
|
||||
border: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
#content #deliverables .actions,
|
||||
#content #milestones .actions{
|
||||
float: right;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
#content #deliverables .actions a,
|
||||
#content #milestones .actions a{
|
||||
font-size: 13px;
|
||||
color: #3e3e3e;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
#deliverables table{
|
||||
width: 100%;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#content #deliverables table thead tr th{
|
||||
border-right: 1px solid #e6e6e6;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#content #deliverables table thead tr{
|
||||
border-bottom: 1px solid #e6e6e6;
|
||||
}
|
||||
|
||||
#content #deliverables table th,
|
||||
#content #deliverables table td{
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
|
||||
#content #deliverables table td, #content #deliverables table th,
|
||||
#content #milestones table td, #content #milestones table th,
|
||||
#content #contract_list table td, #content #contract_list table th {
|
||||
border:1px solid #e6e6e6;
|
||||
border-style: solid;
|
||||
text-align:left;
|
||||
position: static;
|
||||
vertical-align:top;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
#content #deliverables table tr.noborder td{
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
#content #deliverables table tr.ign td{
|
||||
border-top: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#content #deliverables table tr.ign td table td{
|
||||
padding: 2px 5px 2px 5px;
|
||||
}
|
||||
|
||||
#content #deliverables table tr{
|
||||
background-color: #edf6fa;
|
||||
}
|
||||
|
||||
#content #deliverables table tr td.white{
|
||||
background-color: #f6fafd;
|
||||
}
|
||||
|
||||
#content #deliverables table tr.even,
|
||||
#content #deliverables table tr.even:hover {
|
||||
background-color:#dff3fc;
|
||||
}
|
||||
|
||||
#content #deliverables table tr.ign tr{
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
|
||||
#content #deliverables div.title{
|
||||
background: #FFF;
|
||||
padding: 6px;
|
||||
border-bottom: 1px solid #e4eff4;
|
||||
}
|
||||
#content #deliverables .title a {
|
||||
margin-right: 6px;
|
||||
}
|
||||
#content #deliverables .title img{
|
||||
vertical-align: middle;
|
||||
|
||||
}
|
||||
|
||||
#content #deliverables .click td{
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#content #deliverables .expanded{
|
||||
border: 1px solid #c8d0d4;
|
||||
margin: 5px;
|
||||
margin-top: 0;
|
||||
background: #f6fbfd;
|
||||
}
|
||||
|
||||
#content #deliverables .expanded fieldset{
|
||||
border: none;
|
||||
}
|
||||
|
||||
#content #deliverables .info{
|
||||
width: 45%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
#content #deliverables .info p{
|
||||
margin: 10px 0 10px 10px;
|
||||
}
|
||||
#content #deliverables .info form fieldset{
|
||||
margin-left: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#content #deliverables .info table{
|
||||
width: auto;
|
||||
margin: 0 0 0 10px;
|
||||
}
|
||||
#content #deliverables .info table td{
|
||||
border: 0;
|
||||
padding: 2px 5px 2px 5px;
|
||||
}
|
||||
|
||||
#content #deliverables .finance table{
|
||||
border-left: 1px solid #e4eff4;
|
||||
}
|
||||
|
||||
#content #deliverables .finance table td,
|
||||
#content #deliverables .issue_status table td{
|
||||
border: 0px;
|
||||
border-right: 1px solid #e4eff4;
|
||||
text-align: right;
|
||||
padding: 2px 5px 2px 5px;
|
||||
}
|
||||
|
||||
#content #deliverables .finance table td.l,
|
||||
#content #deliverables .issue_status table td.l{
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#content #deliverables .finance{
|
||||
float: left;
|
||||
width: 39%;
|
||||
}
|
||||
#content #deliverables .finance table{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#content #deliverables .finance table thead th,
|
||||
#content #deliverables .issue_status table thead th{
|
||||
background: #FFF;
|
||||
border: 0;
|
||||
font-weight: bold;
|
||||
border-bottom: 1px solid #e4eff4;
|
||||
text-align: center;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
#content #deliverables .finance table thead th{
|
||||
border-right: 1px solid #e4eff4;
|
||||
}
|
||||
|
||||
#content #deliverables .finance table tbody tr.total td,
|
||||
#contract-terms table tbody tr.total td{
|
||||
border-top: 1px solid #bed3dd;
|
||||
}
|
||||
|
||||
#content #deliverables .issue_status{
|
||||
float: left;
|
||||
width: 16%;
|
||||
}
|
||||
|
||||
#content #deliverables .issue_status table tbody tr td{
|
||||
border-right: 0;
|
||||
color: #277d94;
|
||||
text-align: left;
|
||||
}
|
||||
#content #deliverables .issue_status table tbody tr td.number {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
|
||||
#content #deliverables a,
|
||||
#content .c_overview a{
|
||||
color: #277d94;
|
||||
}
|
||||
|
||||
#content #milestones .options{
|
||||
float: left;
|
||||
width: 300px;
|
||||
margin-top: 20px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
#content #milestones table{
|
||||
margin: 0;padding: 0;
|
||||
}
|
||||
|
||||
#content #milestones table thead th{
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#content #milestones table tr.odd{
|
||||
background: #dff3fc;
|
||||
}
|
||||
|
||||
#content #milestones table tr.even{
|
||||
background: #edf6fa;
|
||||
}
|
||||
|
||||
#content #milestones table tr.highlight td{
|
||||
border-top: 2px solid #5fccf9;
|
||||
}
|
||||
|
||||
#content #milestones .c{
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
#edit_contract_1 input#contract_start_date,
|
||||
#edit_contract_1 input#contract_end_date{
|
||||
width: 85px;
|
||||
}
|
||||
|
||||
#edit_contract_1 li#contract_billable_rate_input div{
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ en:
|
||||
field_account_executive_short: "Acct. Mgr."
|
||||
field_end_date: "End Date"
|
||||
text_new_contract: "New Contract"
|
||||
text_edit_contract_name: "Edit {{name}}"
|
||||
field_billable_rate: "Billable Rate"
|
||||
field_billable_rate_hint: "$"
|
||||
field_discount: "Discount"
|
||||
@@ -22,6 +23,7 @@ en:
|
||||
text_payment_terms_net_45: "Net 45"
|
||||
button_add_new: Add New
|
||||
text_new_deliverable: New Deliverable
|
||||
text_edit_deliverable_title: "Edit {{title}}"
|
||||
field_manager: Manager
|
||||
field_labor: Labor
|
||||
field_overhead: Overhead
|
||||
@@ -50,3 +52,12 @@ en:
|
||||
field_total_budget: "Total Budget"
|
||||
field_total_spent: "Contract Total"
|
||||
field_contract_type: "Type"
|
||||
field_deliverable: "Deliverable"
|
||||
field_deliverable_plural: "Deliverables"
|
||||
text_terms_and_financial_overview: "Contract Terms and Financial Overview"
|
||||
text_general_legend: "General"
|
||||
text_budget_legend: "Budget"
|
||||
text_account_legend: "Account Management"
|
||||
text_deliverable_details_legend: "Deliverable Details"
|
||||
text_save_contract: "Save Contract"
|
||||
|
||||
|
||||
@@ -66,3 +66,9 @@ Dispatcher.to_prepare :redmine_contracts do
|
||||
end
|
||||
|
||||
require 'redmine_contracts/hooks/view_layouts_base_html_head_hook'
|
||||
require 'redmine_contracts/hooks/view_issues_show_details_bottom_hook'
|
||||
require 'redmine_contracts/hooks/view_issues_form_details_bottom_hook'
|
||||
require 'redmine_contracts/hooks/controller_issues_edit_before_save_hook'
|
||||
require 'redmine_contracts/hooks/view_issues_bulk_edit_details_bottom_hook'
|
||||
require 'redmine_contracts/hooks/controller_issues_bulk_edit_before_save_hook'
|
||||
require 'redmine_contracts/hooks/helper_issues_show_detail_after_setting_hook'
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'pp'
|
||||
|
||||
module RedmineContracts
|
||||
class BudgetPluginInstalledError < StandardError; end
|
||||
|
||||
@@ -7,10 +5,6 @@ module RedmineContracts
|
||||
set_table_name 'deliverables'
|
||||
end
|
||||
|
||||
# TODO: decide how this is activated.
|
||||
# Have the user dump yaml themselves? Or rename the tables and
|
||||
# SQL select the data out into yaml?
|
||||
# Deliverable.all.collect {|d| d.attributes}.to_yaml
|
||||
class BudgetPluginMigration
|
||||
@@data = nil
|
||||
|
||||
@@ -82,8 +76,17 @@ module RedmineContracts
|
||||
end
|
||||
end
|
||||
|
||||
@deliverable_mapper.each do |old, new|
|
||||
Issue.update_all(["deliverable_id = ?", new], ["deliverable_id = ?", old])
|
||||
# Slower than update_all but update_all could potentially hit an issue
|
||||
# multiple times depending on the migration order. Example:
|
||||
#
|
||||
# - Issue 1 has Deliverable 1
|
||||
# - Deliverable 1 updates Issue 1 to have the new deliverable id of 3
|
||||
# - Deliverable 3 runs and updates Issue 1 again to have the new deliverable id of 5
|
||||
#
|
||||
Issue.all.each do |issue|
|
||||
next if issue.deliverable_id.blank?
|
||||
|
||||
issue.update_attribute(:deliverable_id, @deliverable_mapper[issue.deliverable_id])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
module RedmineContracts
|
||||
module Hooks
|
||||
class ControllerIssuesBulkEditBeforeSaveHook < Redmine::Hook::ViewListener
|
||||
# Context:
|
||||
# * :issue => Issue being saved
|
||||
# * :params => HTML parameters
|
||||
#
|
||||
def controller_issues_bulk_edit_before_save(context={})
|
||||
case
|
||||
when context[:params][:deliverable_id].blank?
|
||||
# Do nothing
|
||||
when context[:params][:deliverable_id] == 'none'
|
||||
# Unassign deliverable
|
||||
context[:issue].deliverable = nil
|
||||
else
|
||||
context[:issue].deliverable = Deliverable.find(context[:params][:deliverable_id])
|
||||
end
|
||||
|
||||
return ''
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,25 @@
|
||||
module RedmineContracts
|
||||
module Hooks
|
||||
class ControllerIssuesEditBeforeSaveHook < Redmine::Hook::ViewListener
|
||||
def controller_issues_edit_before_save(context={})
|
||||
|
||||
if context[:params] && context[:params][:issue]
|
||||
if context[:params][:issue][:deliverable_id].present?
|
||||
deliverable = Deliverable.find_by_id(context[:params][:issue][:deliverable_id])
|
||||
if deliverable.contract.project == context[:issue].project
|
||||
context[:issue].deliverable = deliverable
|
||||
end
|
||||
|
||||
else
|
||||
context[:issue].deliverable = nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return ''
|
||||
end
|
||||
|
||||
alias_method :controller_issues_new_before_save, :controller_issues_edit_before_save
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,23 @@
|
||||
module RedmineContracts
|
||||
module Hooks
|
||||
class HelperIssuesShowDetailAfterSettingHook < Redmine::Hook::ViewListener
|
||||
# Deliverable changes for the journal use the Deliverable subject
|
||||
# instead of the id
|
||||
#
|
||||
# Context:
|
||||
# * :detail => Detail about the journal change
|
||||
#
|
||||
def helper_issues_show_detail_after_setting(context = { })
|
||||
# TODO Later: Overwritting the caller is bad juju
|
||||
if context[:detail].prop_key == 'deliverable_id'
|
||||
d = Deliverable.find_by_id(context[:detail].value)
|
||||
context[:detail].value = d.title if d.present? && d.title.present?
|
||||
|
||||
d = Deliverable.find_by_id(context[:detail].old_value)
|
||||
context[:detail].old_value = d.title if d.present? && d.title.present?
|
||||
end
|
||||
''
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,9 @@
|
||||
module RedmineContracts
|
||||
module Hooks
|
||||
class ViewIssuesBulkEditDetailsBottomHook < Redmine::Hook::ViewListener
|
||||
|
||||
render_on(:view_issues_bulk_edit_details_bottom, :partial => 'issues/bulk_edit_deliverable', :layout => false)
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,7 @@
|
||||
module RedmineContracts
|
||||
module Hooks
|
||||
class ViewIssuesFormDetailsBottomHook < Redmine::Hook::ViewListener
|
||||
render_on(:view_issues_form_details_bottom, :partial => 'issues/edit_deliverable', :layout => false)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,9 @@
|
||||
module RedmineContracts
|
||||
module Hooks
|
||||
class ViewIssuesShowDetailsBottomHook < Redmine::Hook::ViewListener
|
||||
include Redmine::I18n
|
||||
|
||||
render_on(:view_issues_show_details_bottom, :partial => 'issues/show_deliverable', :layout => false)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -175,6 +175,7 @@ class BudgetPluginMigrationTest < ActionController::IntegrationTest
|
||||
setup do
|
||||
@issue1 = Issue.generate_for_project!(@project_two, :deliverable_id => 2)
|
||||
@issue2 = Issue.generate_for_project!(@project_two, :deliverable_id => 4)
|
||||
@issue3 = Issue.generate_for_project!(@project_one, :deliverable_id => 1)
|
||||
|
||||
end
|
||||
|
||||
@@ -189,7 +190,9 @@ class BudgetPluginMigrationTest < ActionController::IntegrationTest
|
||||
RedmineContracts::BudgetPluginMigration.migrate(@data)
|
||||
|
||||
# The "third" deliverable has an id of 4
|
||||
assert_equal "Deliverable 2", @issue1.reload.deliverable.title
|
||||
assert_equal "Version 1.0", @issue2.reload.deliverable.title
|
||||
assert_equal "Deliverable One", @issue3.reload.deliverable.title
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -5,7 +5,10 @@ class ContractsEditTest < ActionController::IntegrationTest
|
||||
|
||||
def setup
|
||||
@project = Project.generate!(:identifier => 'main')
|
||||
@contract = Contract.generate!(:project => @project, :name => 'A Contract', :payment_terms => 'net_15')
|
||||
@account_executive = User.generate!
|
||||
@role = Role.generate!
|
||||
User.add_to_project(@account_executive, @project, @role)
|
||||
@contract = Contract.generate!(:project => @project, :name => 'A Contract', :payment_terms => 'net_15', :account_executive => @account_executive)
|
||||
end
|
||||
|
||||
should "allow any user to edit the contract" do
|
||||
@@ -17,7 +20,7 @@ class ContractsEditTest < ActionController::IntegrationTest
|
||||
assert_response :success
|
||||
assert_template 'contracts/edit'
|
||||
|
||||
assert_select "h2", :text => @contract.name
|
||||
assert_select "h2", :text => /#{@contract.name}/
|
||||
assert_select "form#edit_contract_#{@contract.id}.contract" do
|
||||
assert_select "input[value=?]", /#{@contract.name}/
|
||||
assert_select "select#contract_payment_terms" do
|
||||
@@ -26,7 +29,7 @@ class ContractsEditTest < ActionController::IntegrationTest
|
||||
end
|
||||
|
||||
fill_in "Name", :with => 'An updated name'
|
||||
click_button "Update Contract"
|
||||
click_button "Save Contract"
|
||||
|
||||
assert_response :success
|
||||
assert_template 'contracts/show'
|
||||
|
||||
@@ -17,6 +17,8 @@ class ContractsNewTest < ActionController::IntegrationTest
|
||||
|
||||
should "create a new contract" do
|
||||
@account_executive = User.generate!
|
||||
@role = Role.generate!
|
||||
User.add_to_project(@account_executive, @project, @role)
|
||||
|
||||
visit_contracts_for_project(@project)
|
||||
click_link 'New Contract'
|
||||
@@ -28,7 +30,7 @@ class ContractsNewTest < ActionController::IntegrationTest
|
||||
fill_in "End Date", :with => '2010-12-31'
|
||||
select "Net 30", :from => "Payment Terms"
|
||||
|
||||
click_button "Create Contract"
|
||||
click_button "Save Contract"
|
||||
|
||||
assert_response :success
|
||||
assert_template 'contracts/show'
|
||||
|
||||
@@ -15,7 +15,7 @@ class ContractsShowTest < ActionController::IntegrationTest
|
||||
assert_template 'contracts/show'
|
||||
assert_equal "/projects/main/contracts/#{@contract.id}", current_url
|
||||
|
||||
assert_select "div#contract_#{@contract.id}.contract" do
|
||||
assert_select "div.title-bar" do
|
||||
assert_select 'h2', :text => @contract.name
|
||||
end
|
||||
end
|
||||
|
||||
@@ -13,7 +13,7 @@ class DeliverablesDeleteTest < ActionController::IntegrationTest
|
||||
should "allow anyone to delete the deliverable" do
|
||||
visit_contract_page(@contract)
|
||||
|
||||
click_link_within "#fixed_deliverable_#{@deliverable.id}", 'Delete'
|
||||
click_link_within "#deliverable_details_#{@deliverable.id}", 'Delete'
|
||||
assert_response :success
|
||||
assert_template 'contracts/show'
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ class DeliverablesEditTest < ActionController::IntegrationTest
|
||||
|
||||
should "allow any user to edit the Fixed deliverable" do
|
||||
visit_contract_page(@contract)
|
||||
click_link_within "#fixed_deliverable_#{@fixed_deliverable.id}", 'Edit'
|
||||
click_link_within "#deliverable_details_#{@fixed_deliverable.id}", 'Edit'
|
||||
assert_response :success
|
||||
assert_template 'deliverables/edit'
|
||||
|
||||
@@ -45,7 +45,7 @@ class DeliverablesEditTest < ActionController::IntegrationTest
|
||||
|
||||
should "allow any user to edit the Hourly deliverable" do
|
||||
visit_contract_page(@contract)
|
||||
click_link_within "#hourly_deliverable_#{@hourly_deliverable.id}", 'Edit'
|
||||
click_link_within "#deliverable_details_#{@hourly_deliverable.id}", 'Edit'
|
||||
assert_response :success
|
||||
assert_template 'deliverables/edit'
|
||||
|
||||
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
require File.dirname(__FILE__) + '/../../../test_helper'
|
||||
|
||||
class RedmineContracts::Hooks::ControllerIssuesBulkEditBeforeSaveHookTest < ActionController::IntegrationTest
|
||||
include Redmine::Hook::Helper
|
||||
|
||||
context "#view_issues_bulk_edit_details_bottom" do
|
||||
setup do
|
||||
@project = Project.generate!
|
||||
@issue = Issue.generate_for_project!(@project)
|
||||
@issue2 = Issue.generate_for_project!(@project)
|
||||
@issue3 = Issue.generate_for_project!(@project)
|
||||
@issues = [@issue, @issue2, @issue3]
|
||||
@contract1 = Contract.generate!(:project => @project)
|
||||
@contract2 = Contract.generate!(:project => @project)
|
||||
|
||||
@manager = User.generate!(:login => 'manager', :password => 'existing', :password_confirmation => 'existing')
|
||||
@role = Role.generate!(:permissions => [:view_issues, :edit_issues])
|
||||
User.add_to_project(@manager, @project, @role)
|
||||
@deliverable1 = FixedDeliverable.generate!(:contract => @contract1, :manager => @manager, :title => 'The Title 1')
|
||||
@deliverable2 = FixedDeliverable.generate!(:contract => @contract2, :manager => @manager, :title => 'The Title 2')
|
||||
@issue.deliverable = @deliverable1
|
||||
|
||||
login_as('manager', 'existing')
|
||||
end
|
||||
|
||||
context "when saving multiple issues" do
|
||||
setup do
|
||||
visit_issue_bulk_edit_page(@issues)
|
||||
end
|
||||
|
||||
should "allow clearing all of the deliverables" do
|
||||
select "none", :from => "Deliverable"
|
||||
click_button "Submit"
|
||||
|
||||
assert_response :success
|
||||
|
||||
@issues.each do |issue|
|
||||
assert_equal nil, issue.reload.deliverable
|
||||
end
|
||||
end
|
||||
|
||||
should "allow assigning a deliverable" do
|
||||
select @deliverable2.title, :from => "Deliverable"
|
||||
click_button "Submit"
|
||||
|
||||
assert_response :success
|
||||
|
||||
@issues.each do |issue|
|
||||
assert_equal @deliverable2, issue.reload.deliverable
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,59 @@
|
||||
require File.dirname(__FILE__) + '/../../../test_helper'
|
||||
|
||||
class RedmineContracts::Hooks::ControllerIssuesEditBeforeSaveTest < ActionController::IntegrationTest
|
||||
include Redmine::Hook::Helper
|
||||
|
||||
context "#controller_issues_edit_before_save" do
|
||||
setup do
|
||||
@project = Project.generate!
|
||||
IssueStatus.generate!(:is_default => true)
|
||||
@issue = Issue.generate_for_project!(@project)
|
||||
@contract1 = Contract.generate!(:project => @project)
|
||||
@contract2 = Contract.generate!(:project => @project)
|
||||
|
||||
@manager = User.generate!(:login => 'manager', :password => 'existing', :password_confirmation => 'existing', :admin => true)
|
||||
@role = Role.generate!(:permissions => [:view_issues, :add_issues, :edit_issues])
|
||||
User.add_to_project(@manager, @project, @role)
|
||||
@deliverable1 = FixedDeliverable.generate!(:contract => @contract1, :manager => @manager, :title => 'The Title for 1')
|
||||
@deliverable2 = FixedDeliverable.generate!(:contract => @contract2, :manager => @manager, :title => 'The Title for 2')
|
||||
|
||||
login_as('manager', 'existing')
|
||||
@project.reload
|
||||
end
|
||||
|
||||
context "for a new issue" do
|
||||
setup do
|
||||
visit_project(@project)
|
||||
click_link "New issue"
|
||||
end
|
||||
|
||||
should "set the issue's deliverable" do
|
||||
fill_in "Subject", :with => 'Hook test'
|
||||
select @deliverable2.title, :from => "Deliverable"
|
||||
click_button "Create"
|
||||
|
||||
assert_response :success
|
||||
|
||||
assert_equal @deliverable2, Issue.last.deliverable
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
context "for an existing issue" do
|
||||
setup do
|
||||
visit_issue_page(@issue)
|
||||
end
|
||||
|
||||
should "update the issue's deliverable" do
|
||||
select @deliverable2.title, :from => "Deliverable"
|
||||
click_button "Submit"
|
||||
|
||||
assert_response :success
|
||||
|
||||
@issue.reload
|
||||
assert_equal @deliverable2, @issue.deliverable
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
require File.dirname(__FILE__) + '/../../../test_helper'
|
||||
|
||||
class RedmineContracts::Hooks::HelperIssuesShowDetailAfterSettingHookTest < ActionController::IntegrationTest
|
||||
include Redmine::Hook::Helper
|
||||
|
||||
context "#helper_issues_show_detail_after_setting" do
|
||||
setup do
|
||||
@project = Project.generate!
|
||||
@issue = Issue.generate_for_project!(@project)
|
||||
|
||||
@contract1 = Contract.generate!(:project => @project)
|
||||
@contract2 = Contract.generate!(:project => @project)
|
||||
|
||||
@manager = User.generate!(:login => 'manager', :password => 'existing', :password_confirmation => 'existing')
|
||||
@role = Role.generate!(:permissions => [:view_issues, :edit_issues])
|
||||
User.add_to_project(@manager, @project, @role)
|
||||
@deliverable1 = FixedDeliverable.generate!(:contract => @contract1, :manager => @manager, :title => 'The Title 1')
|
||||
@deliverable2 = FixedDeliverable.generate!(:contract => @contract2, :manager => @manager, :title => 'The Title 2')
|
||||
# Set first
|
||||
@issue.init_journal(@manager)
|
||||
@issue.deliverable = @deliverable1
|
||||
@issue.save!
|
||||
# Change
|
||||
@issue.init_journal(@manager)
|
||||
@issue.deliverable = @deliverable2
|
||||
@issue.save!
|
||||
# Unset
|
||||
@issue.init_journal(@manager)
|
||||
@issue.deliverable = nil
|
||||
@issue.save!
|
||||
|
||||
login_as('manager', 'existing')
|
||||
|
||||
visit_issue_page(@issue)
|
||||
assert_response :success
|
||||
end
|
||||
|
||||
should "show when a deliverable is set" do
|
||||
assert_select ".details" do
|
||||
assert_select "li", :text => /Deliverable set to #{@deliverable1.title}/
|
||||
end
|
||||
end
|
||||
|
||||
should "show when a deliverable is changed" do
|
||||
assert_select ".details" do
|
||||
assert_select "li", :text => /Deliverable changed from #{@deliverable1.title} to #{@deliverable2.title}/
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
should "show when a deliverable is removed" do
|
||||
assert_select ".details" do
|
||||
assert_select "li", :text => /Deliverable deleted .*#{@deliverable2.title}/
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
require File.dirname(__FILE__) + '/../../../test_helper'
|
||||
|
||||
class RedmineContracts::Hooks::ViewIssuesBulkEditDetailsBottomHookTest < ActionController::IntegrationTest
|
||||
include Redmine::Hook::Helper
|
||||
|
||||
context "#view_issues_bulk_edit_details_bottom" do
|
||||
setup do
|
||||
@project = Project.generate!
|
||||
@issue = Issue.generate_for_project!(@project)
|
||||
@issue2 = Issue.generate_for_project!(@project)
|
||||
@issue3 = Issue.generate_for_project!(@project)
|
||||
@contract1 = Contract.generate!(:project => @project)
|
||||
@contract2 = Contract.generate!(:project => @project)
|
||||
|
||||
@manager = User.generate!(:login => 'manager', :password => 'existing', :password_confirmation => 'existing')
|
||||
@role = Role.generate!(:permissions => [:view_issues, :edit_issues])
|
||||
User.add_to_project(@manager, @project, @role)
|
||||
@deliverable1 = FixedDeliverable.generate!(:contract => @contract1, :manager => @manager, :title => 'The Title')
|
||||
@deliverable2 = FixedDeliverable.generate!(:contract => @contract2, :manager => @manager, :title => 'The Title')
|
||||
@issue.deliverable = @deliverable1
|
||||
|
||||
login_as('manager', 'existing')
|
||||
end
|
||||
|
||||
context "with Contracts Enabled" do
|
||||
setup do
|
||||
visit_issue_bulk_edit_page([@issue, @issue2, @issue3])
|
||||
end
|
||||
|
||||
should "render the a select field for the deliverables with all of the deliverables grouped by contract" do
|
||||
|
||||
assert_select "select#deliverable_id" do
|
||||
assert_select "optgroup[label=?]", @contract1.name do
|
||||
assert_select "option", :text => /#{@deliverable1.title}/
|
||||
end
|
||||
|
||||
assert_select "optgroup[label=?]", @contract2.name do
|
||||
assert_select "option", :text => /#{@deliverable2.title}/
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with Contracts Disabled" do
|
||||
setup do
|
||||
@project.enabled_modules.collect {|m| m.destroy if m.name == 'contracts' }
|
||||
visit_issue_bulk_edit_page([@issue, @issue2, @issue3])
|
||||
end
|
||||
|
||||
should "not render the deliverable select field" do
|
||||
assert_select 'select#deliverable_id', :count => 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,52 @@
|
||||
require File.dirname(__FILE__) + '/../../../test_helper'
|
||||
|
||||
class RedmineContracts::Hooks::ViewIssuesFormDetailsBottomTest < ActionController::IntegrationTest
|
||||
include Redmine::Hook::Helper
|
||||
|
||||
context "#view_issues_form_details_bottom" do
|
||||
setup do
|
||||
@project = Project.generate!
|
||||
@issue = Issue.generate_for_project!(@project)
|
||||
@contract1 = Contract.generate!(:project => @project)
|
||||
@contract2 = Contract.generate!(:project => @project)
|
||||
|
||||
@manager = User.generate!(:login => 'manager', :password => 'existing', :password_confirmation => 'existing')
|
||||
@role = Role.generate!(:permissions => [:view_issues, :edit_issues])
|
||||
User.add_to_project(@manager, @project, @role)
|
||||
@deliverable1 = FixedDeliverable.generate!(:contract => @contract1, :manager => @manager, :title => 'The Title')
|
||||
@deliverable2 = FixedDeliverable.generate!(:contract => @contract2, :manager => @manager, :title => 'The Title')
|
||||
@issue.deliverable = @deliverable1
|
||||
|
||||
login_as('manager', 'existing')
|
||||
end
|
||||
|
||||
context "with Contracts Enabled" do
|
||||
setup do
|
||||
visit_issue_page(@issue)
|
||||
end
|
||||
|
||||
should "render the a select field for the deliverables with all of the deliverables grouped by contract" do
|
||||
assert_select "select#issue_deliverable_id" do
|
||||
assert_select "optgroup[label=?]", @contract1.name do
|
||||
assert_select "option", :text => /#{@deliverable1.title}/
|
||||
end
|
||||
|
||||
assert_select "optgroup[label=?]", @contract2.name do
|
||||
assert_select "option", :text => /#{@deliverable2.title}/
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with Contracts Disabled" do
|
||||
setup do
|
||||
@project.enabled_modules.collect {|m| m.destroy if m.name == 'contracts' }
|
||||
visit_issue_page(@issue)
|
||||
end
|
||||
|
||||
should "not render the deliverable select field" do
|
||||
assert_select 'select#issue_deliverable_id', :count => 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -71,6 +71,14 @@ module IntegrationTestHelper
|
||||
assert_template 'contracts/show'
|
||||
end
|
||||
|
||||
def visit_issue_page(issue)
|
||||
visit '/issues/' + issue.id.to_s
|
||||
end
|
||||
|
||||
def visit_issue_bulk_edit_page(issues)
|
||||
visit url_for(:controller => 'issues', :action => 'bulk_edit', :ids => issues.collect(&:id))
|
||||
end
|
||||
|
||||
def assert_forbidden
|
||||
assert_response :forbidden
|
||||
assert_template 'common/403'
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
require File.dirname(__FILE__) + '/../../../../test_helper'
|
||||
|
||||
class RedmineContracts::Hooks::ViewIssuesShowDetailsBottomTest < ActionController::TestCase
|
||||
include Redmine::Hook::Helper
|
||||
|
||||
# Bloody bloody hack to work around Rails coupling of _VC.
|
||||
def template
|
||||
t = ActionView::Base.new(ActionController::Base.view_paths, {}, @controller)
|
||||
def t.template_format
|
||||
"html"
|
||||
end
|
||||
|
||||
# Rendered views aren't getting access to the controller's I18n module
|
||||
t.send(:extend, Redmine::I18n)
|
||||
t
|
||||
end
|
||||
|
||||
def controller
|
||||
@controller ||= ApplicationController.new
|
||||
@controller.class.send(:include, ::Redmine::I18n)
|
||||
@controller.response ||= ActionController::TestResponse.new
|
||||
# Hack to support render_on
|
||||
@controller.instance_variable_set('@template', template)
|
||||
@controller.response = response
|
||||
@controller
|
||||
end
|
||||
|
||||
def request
|
||||
@request ||= ActionController::TestRequest.new
|
||||
end
|
||||
|
||||
# Hack to support render_on
|
||||
def response
|
||||
@response.template ||= template
|
||||
@response
|
||||
end
|
||||
|
||||
def hook(args={})
|
||||
call_hook :view_issues_show_details_bottom, args
|
||||
end
|
||||
|
||||
context "#view_issues_show_details_bottom" do
|
||||
setup do
|
||||
@project = Project.generate!
|
||||
@issue = Issue.generate_for_project!(@project)
|
||||
@contract = Contract.generate!(:project => @project)
|
||||
|
||||
@manager = User.generate!
|
||||
@role = Role.generate!
|
||||
User.add_to_project(@manager, @project, @role)
|
||||
@deliverable = FixedDeliverable.generate!(:contract => @contract, :manager => @manager, :title => 'The Title')
|
||||
@issue.deliverable = @deliverable
|
||||
end
|
||||
|
||||
context "with Contracts Enabled" do
|
||||
should "render the deliverable's name" do
|
||||
@response.body = hook(:project => @project, :issue => @issue, :controller => controller)
|
||||
|
||||
assert_select "tr" do
|
||||
assert_select "td", :text => /#{@deliverable.title}/
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with Contracts Disabled" do
|
||||
setup do
|
||||
@project.enabled_modules.destroy_all
|
||||
end
|
||||
|
||||
should "not render the deliverable's name" do
|
||||
@response.body = hook(:project => @project, :issue => @issue, :controller => controller)
|
||||
|
||||
assert_no_match /#{@deliverable.title}/, @response.body
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user