Merge branch '6441-contract-and-deliverable-status'
This commit is contained in:
commit
066f46b9bf
29 files changed
+1258
-53
No files matched your search
@@ -1,12 +1,52 @@
|
|||||||
module ContractsHelper
|
module ContractsHelper
|
||||||
def setup_nested_deliverable_records(deliverable)
|
def setup_nested_deliverable_records(deliverable)
|
||||||
returning(deliverable) do |d|
|
deliverable.labor_budgets.build if deliverable.labor_budgets.empty?
|
||||||
d.labor_budgets.build if d.labor_budgets.empty?
|
deliverable.overhead_budgets.build if deliverable.overhead_budgets.empty?
|
||||||
d.overhead_budgets.build if d.overhead_budgets.empty?
|
deliverable.fixed_budgets.build if deliverable.fixed_budgets.empty?
|
||||||
d.fixed_budgets.build if d.fixed_budgets.empty?
|
deliverable
|
||||||
|
end
|
||||||
|
|
||||||
|
def group_contracts_by_status(contracts)
|
||||||
|
grouped_contracts = contracts.inject({}) do |grouped, contract|
|
||||||
|
grouped[contract.status] ||= []
|
||||||
|
grouped[contract.status] << contract
|
||||||
|
grouped
|
||||||
|
end
|
||||||
|
grouped_contracts["open"] ||= []
|
||||||
|
grouped_contracts["locked"] ||= []
|
||||||
|
grouped_contracts["closed"] ||= []
|
||||||
|
grouped_contracts
|
||||||
|
end
|
||||||
|
|
||||||
|
def grouped_deliverable_options_for_select(project, selected_key=nil)
|
||||||
|
project.contracts.all(:include => :deliverables).inject("") do |html, contract|
|
||||||
|
if contract.closed? && !contract.includes_deliverable_id?(selected_key)
|
||||||
|
html
|
||||||
|
else
|
||||||
|
html << content_tag(:optgroup,
|
||||||
|
deliverable_options_for_contract(contract, selected_key).join("\n"),
|
||||||
|
:label => h(contract.name))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def deliverable_options_for_contract(contract, selected_key)
|
||||||
|
contract.deliverables.collect do |deliverable|
|
||||||
|
deliverable_option(deliverable, selected_key)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def deliverable_option(deliverable, selected_key)
|
||||||
|
option_attributes = {}
|
||||||
|
option_attributes[:value] = h(deliverable.id)
|
||||||
|
option_attributes[:selected] = "selected" if selected_key.to_i == deliverable.id
|
||||||
|
option_attributes[:disabled] = "disabled" if (deliverable.locked? || deliverable.contract_locked?) && selected_key.to_i != deliverable.id
|
||||||
|
|
||||||
|
return "" if deliverable.closed? && option_attributes[:selected].blank? # Skip unselected, closed
|
||||||
|
|
||||||
|
content_tag(:option, h(deliverable.title), option_attributes)
|
||||||
|
end
|
||||||
|
|
||||||
# Simple helper to show the values of a field on an object in a standard format
|
# Simple helper to show the values of a field on an object in a standard format
|
||||||
#
|
#
|
||||||
# <p>
|
# <p>
|
||||||
|
|||||||
+72
-9
@@ -17,7 +17,9 @@ class Contract < ActiveRecord::Base
|
|||||||
validates_presence_of :start_date
|
validates_presence_of :start_date
|
||||||
validates_presence_of :end_date
|
validates_presence_of :end_date
|
||||||
validates_inclusion_of :discount_type, :in => %w($ %), :allow_blank => true, :allow_nil => true
|
validates_inclusion_of :discount_type, :in => %w($ %), :allow_blank => true, :allow_nil => true
|
||||||
|
validates_inclusion_of :status, :in => ["open","locked","closed"], :allow_blank => true, :allow_nil => true
|
||||||
validate :start_and_end_date_are_valid
|
validate :start_and_end_date_are_valid
|
||||||
|
validate_on_update :validate_status_changes
|
||||||
|
|
||||||
# Accessors
|
# Accessors
|
||||||
attr_accessible :name
|
attr_accessible :name
|
||||||
@@ -33,15 +35,49 @@ class Contract < ActiveRecord::Base
|
|||||||
attr_accessible :po_number
|
attr_accessible :po_number
|
||||||
attr_accessible :client_point_of_contact
|
attr_accessible :client_point_of_contact
|
||||||
attr_accessible :details
|
attr_accessible :details
|
||||||
|
attr_accessible :status
|
||||||
|
|
||||||
named_scope :by_name, {:order => "#{Contract.table_name}.name ASC"}
|
named_scope :by_name, {:order => "#{Contract.table_name}.name ASC"}
|
||||||
|
named_scope :with_status, lambda {|statuses|
|
||||||
[:status, :contract_type,
|
{
|
||||||
|
:conditions => ["#{Contract.table_name}.status IN (?)", statuses]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[:contract_type,
|
||||||
:discount_spent, :discount_budget
|
:discount_spent, :discount_budget
|
||||||
].each do |mthd|
|
].each do |mthd|
|
||||||
define_method(mthd) { "TODO in later release" }
|
define_method(mthd) { "TODO in later release" }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def status
|
||||||
|
read_attribute(:status) || "open"
|
||||||
|
end
|
||||||
|
|
||||||
|
def lock!
|
||||||
|
update_attribute(:status, "locked")
|
||||||
|
end
|
||||||
|
|
||||||
|
def close!
|
||||||
|
update_attribute(:status, "closed")
|
||||||
|
end
|
||||||
|
|
||||||
|
def open?
|
||||||
|
self.status == "open"
|
||||||
|
end
|
||||||
|
|
||||||
|
def locked?
|
||||||
|
self.status == "locked"
|
||||||
|
end
|
||||||
|
|
||||||
|
def closed?
|
||||||
|
self.status == "closed"
|
||||||
|
end
|
||||||
|
|
||||||
|
def includes_deliverable_id?(deliverable_id)
|
||||||
|
deliverable_ids.include?(deliverable_id.to_i)
|
||||||
|
end
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
# Labor Methods
|
# Labor Methods
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
@@ -229,6 +265,7 @@ class Contract < ActiveRecord::Base
|
|||||||
|
|
||||||
def after_initialize
|
def after_initialize
|
||||||
self.executed = false unless self.executed.present?
|
self.executed = false unless self.executed.present?
|
||||||
|
self.status = "open" unless self.status.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
# Are the start_date and end_date valid?
|
# Are the start_date and end_date valid?
|
||||||
@@ -238,6 +275,30 @@ class Contract < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def valid_status_change?
|
||||||
|
change_to_status_only? || changing_to_the_open_status? || changing_from_the_open_status?
|
||||||
|
end
|
||||||
|
|
||||||
|
def change_to_status_only?
|
||||||
|
["status"] == changes.keys
|
||||||
|
end
|
||||||
|
|
||||||
|
def changing_to_the_open_status?
|
||||||
|
changes["status"].present? && "open" == changes["status"].second
|
||||||
|
end
|
||||||
|
|
||||||
|
def changing_from_the_open_status?
|
||||||
|
changes["status"].present? && "open" == changes["status"].first
|
||||||
|
end
|
||||||
|
|
||||||
|
# TODO: duplicated on Deliverable, refactor after one more duplication
|
||||||
|
def validate_status_changes
|
||||||
|
return if valid_status_change?
|
||||||
|
|
||||||
|
errors.add_to_base(:cant_update_locked_contract) if locked?
|
||||||
|
errors.add_to_base(:cant_update_closed_contract) if closed?
|
||||||
|
end
|
||||||
|
|
||||||
# Currency amount of time that is logged to the project or to issues
|
# Currency amount of time that is logged to the project or to issues
|
||||||
# that are not assigned to a Deliverable
|
# that are not assigned to a Deliverable
|
||||||
def orphaned_time
|
def orphaned_time
|
||||||
@@ -252,15 +313,17 @@ class Contract < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
if Rails.env.test?
|
if Rails.env.test?
|
||||||
generator_for :name, :method => :next_name
|
generator_for :name, :start => "Contract 0000"
|
||||||
generator_for :executed => true
|
generator_for :executed => true
|
||||||
generator_for(:start_date) { Date.yesterday }
|
generator_for(:start_date) { Date.yesterday }
|
||||||
generator_for(:end_date) { Date.tomorrow }
|
generator_for(:end_date) { Date.tomorrow }
|
||||||
|
generator_for :discount, ''
|
||||||
def self.next_name
|
generator_for :details, ''
|
||||||
@last_name ||= 'Contract 0000'
|
generator_for :discount_note, ''
|
||||||
@last_name.succ!
|
generator_for :client_point_of_contact, ''
|
||||||
end
|
generator_for :client_ap_contact_information, ''
|
||||||
|
generator_for :po_number, ''
|
||||||
|
generator_for :status, 'open'
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -270,5 +333,5 @@ class Contract < ActiveRecord::Base
|
|||||||
def summarize_associated_values(records, value_method)
|
def summarize_associated_values(records, value_method)
|
||||||
records.inject(0) {|total, record| total += record.send(value_method)}
|
records.inject(0) {|total, record| total += record.send(value_method)}
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
+102
-2
@@ -19,15 +19,27 @@ class Deliverable < ActiveRecord::Base
|
|||||||
validates_presence_of :title
|
validates_presence_of :title
|
||||||
validates_presence_of :type
|
validates_presence_of :type
|
||||||
validates_presence_of :manager
|
validates_presence_of :manager
|
||||||
|
validates_inclusion_of :status, :in => ["open","locked","closed"], :allow_blank => true, :allow_nil => true
|
||||||
|
validate_on_update :validate_status_changes
|
||||||
|
validate :validate_contract_status
|
||||||
|
|
||||||
# Accessors
|
# Accessors
|
||||||
include DollarizedAttribute
|
include DollarizedAttribute
|
||||||
dollarized_attribute :total
|
dollarized_attribute :total
|
||||||
|
|
||||||
delegate :name, :to => :contract, :prefix => true, :allow_nil => true
|
delegate :name, :to => :contract, :prefix => true, :allow_nil => true
|
||||||
|
delegate "open?", :to => :contract, :prefix => true, :allow_nil => true
|
||||||
|
delegate "closed?", :to => :contract, :prefix => true, :allow_nil => true
|
||||||
|
delegate "locked?", :to => :contract, :prefix => true, :allow_nil => true
|
||||||
|
|
||||||
# Callbacks
|
# Callbacks
|
||||||
|
before_destroy :block_on_locked_contracts
|
||||||
|
before_destroy :block_on_closed_contracts
|
||||||
|
|
||||||
|
def after_initialize
|
||||||
|
self.status = "open" unless self.status.present?
|
||||||
|
end
|
||||||
|
|
||||||
# Register callbacks here, on new records the class isn't set so class-specific
|
# Register callbacks here, on new records the class isn't set so class-specific
|
||||||
# callbacks don't fire.
|
# callbacks don't fire.
|
||||||
def after_save
|
def after_save
|
||||||
@@ -37,6 +49,11 @@ class Deliverable < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
named_scope :by_title, {:order => "#{Deliverable.table_name}.title ASC"}
|
named_scope :by_title, {:order => "#{Deliverable.table_name}.title ASC"}
|
||||||
|
named_scope :with_status, lambda {|statuses|
|
||||||
|
{
|
||||||
|
:conditions => ["#{Deliverable.table_name}.status IN (?)", statuses]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def short_type
|
def short_type
|
||||||
''
|
''
|
||||||
@@ -51,6 +68,88 @@ class Deliverable < ActiveRecord::Base
|
|||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def lock!
|
||||||
|
update_attribute(:status, "locked")
|
||||||
|
end
|
||||||
|
|
||||||
|
def close!
|
||||||
|
update_attribute(:status, "closed")
|
||||||
|
end
|
||||||
|
|
||||||
|
def open?
|
||||||
|
self.status == "open"
|
||||||
|
end
|
||||||
|
|
||||||
|
def locked?
|
||||||
|
self.status == "locked"
|
||||||
|
end
|
||||||
|
|
||||||
|
def closed?
|
||||||
|
self.status == "closed"
|
||||||
|
end
|
||||||
|
|
||||||
|
def editable?
|
||||||
|
(new_record? || open?)
|
||||||
|
end
|
||||||
|
|
||||||
|
def valid_status_change?
|
||||||
|
change_to_status_only? || changing_to_the_open_status? || changing_from_the_open_status?
|
||||||
|
end
|
||||||
|
|
||||||
|
def change_to_status_only?
|
||||||
|
["status"] == changes.keys
|
||||||
|
end
|
||||||
|
|
||||||
|
def changing_to_the_open_status?
|
||||||
|
changes["status"].present? && "open" == changes["status"].second
|
||||||
|
end
|
||||||
|
|
||||||
|
def changing_from_the_open_status?
|
||||||
|
changes["status"].present? && "open" == changes["status"].first
|
||||||
|
end
|
||||||
|
|
||||||
|
# TODO: duplicated on Contract, refactor after one more duplication
|
||||||
|
def validate_status_changes
|
||||||
|
return if valid_status_change?
|
||||||
|
|
||||||
|
errors.add_to_base(:cant_update_locked_deliverable) if locked?
|
||||||
|
errors.add_to_base(:cant_update_closed_deliverable) if closed?
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate_contract_status
|
||||||
|
return if contract_open?
|
||||||
|
return if change_to_status_only?
|
||||||
|
|
||||||
|
if contract_locked?
|
||||||
|
if new_record?
|
||||||
|
errors.add_to_base(:cant_create_deliverable_on_locked_contract)
|
||||||
|
else
|
||||||
|
errors.add_to_base(:cant_update_locked_contract)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if contract_closed?
|
||||||
|
if new_record?
|
||||||
|
errors.add_to_base(:cant_create_deliverable_on_closed_contract)
|
||||||
|
else
|
||||||
|
errors.add_to_base(:cant_update_closed_contract)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# No operation method, useful to clean up logic with an optional message
|
||||||
|
# for documentation
|
||||||
|
def noop(message="")
|
||||||
|
end
|
||||||
|
|
||||||
|
def block_on_locked_contracts
|
||||||
|
!contract_locked?
|
||||||
|
end
|
||||||
|
|
||||||
|
def block_on_closed_contracts
|
||||||
|
!contract_closed?
|
||||||
|
end
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
title
|
title
|
||||||
end
|
end
|
||||||
@@ -214,7 +313,8 @@ class Deliverable < ActiveRecord::Base
|
|||||||
|
|
||||||
if Rails.env.test?
|
if Rails.env.test?
|
||||||
generator_for :title, :method => :next_title
|
generator_for :title, :method => :next_title
|
||||||
|
generator_for :status, 'open'
|
||||||
|
|
||||||
def self.next_title
|
def self.next_title
|
||||||
@last_title ||= 'Deliverable 0000'
|
@last_title ||= 'Deliverable 0000'
|
||||||
@last_title.succ!
|
@last_title.succ!
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
|
<% if resource.locked? || resource.closed? %>
|
||||||
|
<div class="error_msg">
|
||||||
|
<p><%= resource.locked? ? l(:text_contract_locked_warning) : l(:text_contract_closed_warning) %></p>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
<div class="box tabular">
|
<div class="box tabular">
|
||||||
<% form.inputs :name => l(:text_general_legend) do %>
|
<% form.inputs :name => l(:text_general_legend) do %>
|
||||||
<%= form.input :name, :required => true %>
|
<%= form.input :name, :required => true %>
|
||||||
|
<%= form.input :status, :required => true, :collection => [["Open","open"],["Locked","locked"],["Closed","closed"]] %>
|
||||||
<%= form.input :account_executive, :required => true, :collection => @project.users.sort %>
|
<%= form.input :account_executive, :required => true, :collection => @project.users.sort %>
|
||||||
<li class="boolean optional">
|
<li class="boolean optional">
|
||||||
<%= label('contract', 'executed') %>
|
<%= label('contract', 'executed') %>
|
||||||
|
|||||||
@@ -12,10 +12,10 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<% if collection.empty? %>
|
<% if group_contracts_by_status(collection)["open"].empty? %>
|
||||||
<p class="nodata"><%= l(:label_no_data) %></p>
|
<p class="nodata"><%= l(:label_no_data) %></p>
|
||||||
<% else %>
|
<% else %>
|
||||||
<table class="list" cellspacing="0" border="0" cellpadding="0" id="contracts">
|
<table class="list open" cellspacing="0" border="0" cellpadding="0" id="contracts">
|
||||||
<thead>
|
<thead>
|
||||||
<th><%= l(:field_id) %></th>
|
<th><%= l(:field_id) %></th>
|
||||||
<th><%= l(:field_name) %></th>
|
<th><%= l(:field_name) %></th>
|
||||||
@@ -26,11 +26,11 @@
|
|||||||
<th><%= l(:field_end_date) %></th>
|
<th><%= l(:field_end_date) %></th>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<% collection.each do |contract| %>
|
<% group_contracts_by_status(collection)["open"].each do |contract| %>
|
||||||
<% content_tag_for(:tr, contract, :class => cycle('','odd')) do %>
|
<% content_tag_for(:tr, contract, :class => cycle('','odd')) do %>
|
||||||
<td class="id"><%= link_to(h(contract.id), contract_path(@project, contract)) %></td>
|
<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="name"><%= link_to(h(contract.name), contract_path(@project, contract)) %></td>
|
||||||
<td><%= release(5, "Contract Status") %></td>
|
<td class="status"><%= h(contract.status) %></td>
|
||||||
<td><%= release(5, "Contract Type") %></td>
|
<td><%= release(5, "Contract Type") %></td>
|
||||||
<td class="account-executive"><%= h contract.account_executive.name %></td>
|
<td class="account-executive"><%= h contract.account_executive.name %></td>
|
||||||
<td class="total-budget"><%= h(format_value_field_for_contracts(contract.total_budget)) %></td>
|
<td class="total-budget"><%= h(format_value_field_for_contracts(contract.total_budget)) %></td>
|
||||||
@@ -42,11 +42,71 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<div class="title-bar">
|
<div class="title-bar">
|
||||||
<h2>Inactive Contracts</h2>
|
<h2>Locked Contracts</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="nodata"><%= l(:label_no_data) %></p>
|
<% if group_contracts_by_status(collection)["locked"].empty? %>
|
||||||
<p><%= release(5, "Contract Status. Split contracts by active and inactive") %></p>
|
<p class="nodata"><%= l(:label_no_data) %></p>
|
||||||
|
<% else %>
|
||||||
|
<table class="list locked" cellspacing="0" border="0" cellpadding="0" id="contracts">
|
||||||
|
<thead>
|
||||||
|
<th><%= l(:field_id) %></th>
|
||||||
|
<th><%= l(:field_name) %></th>
|
||||||
|
<th><%= l(:field_status) %></th>
|
||||||
|
<th><%= l(:field_type) %></th>
|
||||||
|
<th><%= l(:field_account_executive_short) %></th>
|
||||||
|
<th><%= l(:field_total_budget) %></th>
|
||||||
|
<th><%= l(:field_end_date) %></th>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% group_contracts_by_status(collection)["locked"].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="status"><%= h(contract.status) %></td>
|
||||||
|
<td><%= release(5, "Contract Type") %></td>
|
||||||
|
<td class="account-executive"><%= h contract.account_executive.name %></td>
|
||||||
|
<td class="total-budget"><%= h(format_value_field_for_contracts(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>Closed Contracts</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<% if group_contracts_by_status(collection)["closed"].empty? %>
|
||||||
|
<p class="nodata"><%= l(:label_no_data) %></p>
|
||||||
|
<% else %>
|
||||||
|
<table class="list closed" cellspacing="0" border="0" cellpadding="0" id="contracts">
|
||||||
|
<thead>
|
||||||
|
<th><%= l(:field_id) %></th>
|
||||||
|
<th><%= l(:field_name) %></th>
|
||||||
|
<th><%= l(:field_status) %></th>
|
||||||
|
<th><%= l(:field_type) %></th>
|
||||||
|
<th><%= l(:field_account_executive_short) %></th>
|
||||||
|
<th><%= l(:field_total_budget) %></th>
|
||||||
|
<th><%= l(:field_end_date) %></th>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% group_contracts_by_status(collection)["closed"].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="status"><%= h(contract.status) %></td>
|
||||||
|
<td><%= release(5, "Contract Type") %></td>
|
||||||
|
<td class="account-executive"><%= h contract.account_executive.name %></td>
|
||||||
|
<td class="total-budget"><%= h(format_value_field_for_contracts(contract.total_budget)) %></td>
|
||||||
|
<td class="end-date"><%= h format_date(contract.end_date) %></td>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -15,10 +15,7 @@
|
|||||||
|
|
||||||
<div class="c_overview">
|
<div class="c_overview">
|
||||||
<table class="left">
|
<table class="left">
|
||||||
<tr class="contract-status">
|
<%= show_field(resource, :status, :html_options => {:class => 'contract-status'}) %>
|
||||||
<%# show_field(resource, :status, :html_options => {:class => 'contract-status'}) %>
|
|
||||||
<td colspan="2"><%= release(5, "Contract status") %></td>
|
|
||||||
</tr>
|
|
||||||
<%= show_field(resource, :account_executive, :html_options => {:class => 'contract-account-manager'}) %>
|
<%= show_field(resource, :account_executive, :html_options => {:class => 'contract-account-manager'}) %>
|
||||||
<tr class="contract-type">
|
<tr class="contract-type">
|
||||||
<%# show_field(resource, :contract_type, :html_options => {:class => 'contract-type'}) %>
|
<%# show_field(resource, :contract_type, :html_options => {:class => 'contract-type'}) %>
|
||||||
@@ -105,7 +102,7 @@
|
|||||||
<div class="actions">
|
<div class="actions">
|
||||||
<a href="#TODO-release-2"><%= release(2, "CSV") %></a>
|
<a href="#TODO-release-2"><%= release(2, "CSV") %></a>
|
||||||
<a href="#TODO-release?"><%= release(5, "View All/Pagination") %></a>
|
<a href="#TODO-release?"><%= release(5, "View All/Pagination") %></a>
|
||||||
<%= link_to(l(:button_add_new), new_contract_deliverable_path(@project, resource), :id => 'new-deliverable') %>
|
<%= link_to(l(:button_add_new), new_contract_deliverable_path(@project, resource), :id => 'new-deliverable') if resource.open? %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="clear"></div>
|
<div class="clear"></div>
|
||||||
@@ -133,7 +130,7 @@
|
|||||||
<td width="10%" class="arrow end-date"><span><%= h format_date(deliverable.end_date) %></span></td>
|
<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="2%" class="type"><%= h deliverable.short_type %></td>
|
||||||
<td width="25%" class="title"><%= h deliverable.title %></td>
|
<td width="25%" class="title"><%= h deliverable.title %></td>
|
||||||
<td width="15%"><%= release(5, "Deliverable status") %></td>
|
<td width="15%" class="status"><%= h deliverable.status %></td>
|
||||||
<td width="15%" class="manager"><%= h deliverable.manager.try(:name) %></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.labor_budget_spent, deliverable.labor_budget_total, :class => 'labor') %>
|
||||||
<%= format_budget_for_deliverable(deliverable, deliverable.overhead_spent, deliverable.overhead_budget_total, :class => 'overhead') %>
|
<%= format_budget_for_deliverable(deliverable, deliverable.overhead_spent, deliverable.overhead_budget_total, :class => 'overhead') %>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<div class="info">
|
<div class="info">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<%= link_to(l(:button_edit), edit_contract_deliverable_path(@project, contract, deliverable), :class => 'icon icon-edit') %>
|
<%= link_to(l(:button_edit), edit_contract_deliverable_path(@project, contract, deliverable), :class => 'icon icon-edit') %>
|
||||||
<%= link_to(l(:button_delete), contract_deliverable_path(@project, contract, deliverable), :method => :delete, :confirm => l(:text_are_you_sure), :class => 'icon icon-del') %>
|
<%= link_to(l(:button_delete), contract_deliverable_path(@project, contract, deliverable), :method => :delete, :confirm => l(:text_are_you_sure), :class => 'icon icon-del') if contract.open? %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= textilizable(deliverable, :notes) %>
|
<%= textilizable(deliverable, :notes) %>
|
||||||
|
|||||||
@@ -2,6 +2,17 @@
|
|||||||
<%= javascript_tag("var i18nEndDateEmpty = '#{l(:text_end_date_empty)}'") %>
|
<%= javascript_tag("var i18nEndDateEmpty = '#{l(:text_end_date_empty)}'") %>
|
||||||
<%= javascript_tag("var i18nChangedPeriodMessage = '#{l(:text_changed_period_message)}'") %>
|
<%= javascript_tag("var i18nChangedPeriodMessage = '#{l(:text_changed_period_message)}'") %>
|
||||||
|
|
||||||
|
<% if resource.locked? || resource.closed? || resource.contract_locked? || resource.contract_closed? %>
|
||||||
|
<div class="error_msg">
|
||||||
|
<% if resource.contract_locked? || resource.contract_closed? %>
|
||||||
|
<p><%= resource.contract_locked? ? l(:text_contract_locked_warning) : l(:text_contract_closed_warning) %></p>
|
||||||
|
<% end %>
|
||||||
|
<% if resource.locked? || resource.closed? %>
|
||||||
|
<p><%= resource.locked? ? l(:text_deliverable_locked_warning) : l(:text_deliverable_closed_warning) %></p>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
<div class="box tabular">
|
<div class="box tabular">
|
||||||
<% form.inputs :name => l(:text_deliverable_details_legend), :id => 'deliverable-details' do %>
|
<% form.inputs :name => l(:text_deliverable_details_legend), :id => 'deliverable-details' do %>
|
||||||
<%# Used by jquery to check if this is a new or existing record %>
|
<%# Used by jquery to check if this is a new or existing record %>
|
||||||
@@ -19,6 +30,7 @@
|
|||||||
</li>
|
</li>
|
||||||
<%= form.input :type, :as => :hidden, :class => 'type' %>
|
<%= form.input :type, :as => :hidden, :class => 'type' %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
<%= form.input :status, :required => true, :collection => [["Open","open"],["Locked","locked"],["Closed","closed"]] %>
|
||||||
<%= form.input :manager, :required => true, :collection => @project.users.sort %>
|
<%= form.input :manager, :required => true, :collection => @project.users.sort %>
|
||||||
|
|
||||||
<%= form.input :start_date, :as => :string, :input_html => {:size => 10, :class => 'start-date', :id => 'deliverable_start_date'}, :hint => calendar_for('deliverable_start_date') %>
|
<%= form.input :start_date, :as => :string, :input_html => {:size => 10, :class => 'start-date', :id => 'deliverable_start_date'}, :hint => calendar_for('deliverable_start_date') %>
|
||||||
|
|||||||
@@ -1,14 +1,10 @@
|
|||||||
<% if project.module_enabled?(:contracts) && User.current.allowed_to?(:assign_deliverable_to_issue, project) %>
|
<% if project.module_enabled?(:contracts) && User.current.allowed_to?(:assign_deliverable_to_issue, project) %>
|
||||||
<p>
|
<p>
|
||||||
<%= label_tag(:deliverable_id, l(:field_deliverable)) %>
|
<%= 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',
|
<%= select_tag('deliverable_id',
|
||||||
content_tag('option', l(:label_no_change_option), :value => '') +
|
content_tag('option', l(:label_no_change_option), :value => '') +
|
||||||
content_tag('option', l(:label_none), :value => 'none') +
|
content_tag('option', l(:label_none), :value => 'none') +
|
||||||
grouped_options_for_select(options)) %>
|
grouped_deliverable_options_for_select(project)) %>
|
||||||
</p>
|
</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
@@ -1,9 +1,6 @@
|
|||||||
<% if project.module_enabled?(:contracts) && User.current.allowed_to?(:assign_deliverable_to_issue, project) %>
|
<% if project.module_enabled?(:contracts) && User.current.allowed_to?(:assign_deliverable_to_issue, project) %>
|
||||||
<p>
|
<p>
|
||||||
<% options = project.contracts.inject([]) {|data, contract|
|
<%= form.select(:deliverable_id, grouped_deliverable_options_for_select(project, issue.deliverable_id), {:include_blank => true}) %>
|
||||||
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>
|
</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
+19
-1
@@ -1,4 +1,19 @@
|
|||||||
en:
|
en:
|
||||||
|
activerecord:
|
||||||
|
errors:
|
||||||
|
messages:
|
||||||
|
cant_create_time_on_object: "Can't create a time entry on a %{reason} %{thing}"
|
||||||
|
cant_assign_to_closed_deliverable: "Can't assign issue to a closed deliverable"
|
||||||
|
cant_assign_to_locked_deliverable: "Can't assign issue to a locked deliverable"
|
||||||
|
cant_assign_to_closed_contract: "Can't assign issue to a closed contract"
|
||||||
|
cant_assign_to_locked_contract: "Can't assign issue to a locked contract"
|
||||||
|
cant_update_locked_deliverable: "Can't update a locked deliverable"
|
||||||
|
cant_update_closed_deliverable: "Can't update a closed deliverable"
|
||||||
|
cant_update_locked_contract: "Can't update a locked contract"
|
||||||
|
cant_update_closed_contract: "Can't update a closed contract"
|
||||||
|
cant_create_deliverable_on_locked_contract: "Can't create a deliverable on a locked contract"
|
||||||
|
cant_create_deliverable_on_closed_contract: "Can't create a deliverable on a closed contract"
|
||||||
|
|
||||||
field_end_date: End Date
|
field_end_date: End Date
|
||||||
field_executed: Executed
|
field_executed: Executed
|
||||||
text_contracts: Contracts
|
text_contracts: Contracts
|
||||||
@@ -81,4 +96,7 @@ en:
|
|||||||
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."
|
text_error_message_update_orphaned_time: "Please update the orphaned issues."
|
||||||
field_estimated: Estimated
|
field_estimated: Estimated
|
||||||
|
text_deliverable_locked_warning: "This deliverable is locked and cannot be saved without changing it's status to Open."
|
||||||
|
text_deliverable_closed_warning: "This deliverable is closed and cannot be saved without changing it's status to Open."
|
||||||
|
text_contract_locked_warning: "This contract is locked and cannot be saved without changing it's status to Open."
|
||||||
|
text_contract_closed_warning: "This contract is closed and cannot be saved without changing it's status to Open."
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
class AddStatusToContracts < ActiveRecord::Migration
|
||||||
|
def self.up
|
||||||
|
add_column :contracts, :status, :string
|
||||||
|
add_index :contracts, :status
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.down
|
||||||
|
remove_column :contracts, :status
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
class AddStatusToDeliverables < ActiveRecord::Migration
|
||||||
|
def self.up
|
||||||
|
add_column :deliverables, :status, :string
|
||||||
|
add_index :deliverables, :status
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.down
|
||||||
|
remove_column :deliverables, :status
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -62,6 +62,9 @@ end
|
|||||||
|
|
||||||
require 'dispatcher'
|
require 'dispatcher'
|
||||||
Dispatcher.to_prepare :redmine_contracts do
|
Dispatcher.to_prepare :redmine_contracts do
|
||||||
|
|
||||||
|
require_dependency 'time_entry'
|
||||||
|
TimeEntry.send(:include, RedmineContracts::Patches::TimeEntryPatch)
|
||||||
gem 'inherited_resources', :version => '1.0.6'
|
gem 'inherited_resources', :version => '1.0.6'
|
||||||
require_dependency 'inherited_resources'
|
require_dependency 'inherited_resources'
|
||||||
require_dependency 'inherited_resources/base'
|
require_dependency 'inherited_resources/base'
|
||||||
@@ -99,6 +102,9 @@ Dispatcher.to_prepare :redmine_contracts do
|
|||||||
unless Query.available_columns.collect(&:name).include?(:contract_name)
|
unless Query.available_columns.collect(&:name).include?(:contract_name)
|
||||||
Query.add_available_column(QueryColumn.new(:contract_name, :sortable => "#{Contract.table_name}.name", :groupable => 'contracts.name'))
|
Query.add_available_column(QueryColumn.new(:contract_name, :sortable => "#{Contract.table_name}.name", :groupable => 'contracts.name'))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
require_dependency 'application_controller'
|
||||||
|
ApplicationController.send(:helper, :contracts)
|
||||||
end
|
end
|
||||||
|
|
||||||
require 'redmine_contracts/hooks/view_layouts_base_html_head_hook'
|
require 'redmine_contracts/hooks/view_layouts_base_html_head_hook'
|
||||||
|
|||||||
@@ -15,6 +15,24 @@ module RedmineContracts
|
|||||||
def contract_name
|
def contract_name
|
||||||
contract.try(:name)
|
contract.try(:name)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
validate :validate_deliverable_status
|
||||||
|
validate :validate_contract_status
|
||||||
|
|
||||||
|
def validate_deliverable_status
|
||||||
|
if deliverable.present? && changes["deliverable_id"].present?
|
||||||
|
errors.add_to_base(:cant_assign_to_closed_deliverable) if deliverable.closed?
|
||||||
|
errors.add_to_base(:cant_assign_to_locked_deliverable) if deliverable.locked?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate_contract_status
|
||||||
|
if deliverable.present? && changes["deliverable_id"].present? && contract.present?
|
||||||
|
errors.add_to_base(:cant_assign_to_closed_contract) if contract.closed?
|
||||||
|
errors.add_to_base(:cant_assign_to_locked_contract) if contract.locked?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
module RedmineContracts
|
||||||
|
module Patches
|
||||||
|
module TimeEntryPatch
|
||||||
|
def self.included(base)
|
||||||
|
base.extend(ClassMethods)
|
||||||
|
|
||||||
|
base.send(:include, InstanceMethods)
|
||||||
|
base.class_eval do
|
||||||
|
unloadable
|
||||||
|
|
||||||
|
validate :validate_deliverable_status
|
||||||
|
validate :validate_contract_status
|
||||||
|
|
||||||
|
def validate_deliverable_status
|
||||||
|
if issue.present? && issue.deliverable.present?
|
||||||
|
errors.add_to_base("#{l(:"activerecord.errors.messages.cant_create_time_on_object", :reason => 'locked', :thing => 'deliverable')}") if issue.deliverable.locked?
|
||||||
|
errors.add_to_base("#{l(:"activerecord.errors.messages.cant_create_time_on_object", :reason => 'closed', :thing => 'deliverable')}") if issue.deliverable.closed?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate_contract_status
|
||||||
|
if issue.present? && issue.deliverable.present? && issue.deliverable.contract.present?
|
||||||
|
errors.add_to_base("#{l(:"activerecord.errors.messages.cant_create_time_on_object", :reason => 'locked', :thing => 'contract')}") if issue.deliverable.contract.locked?
|
||||||
|
errors.add_to_base("#{l(:"activerecord.errors.messages.cant_create_time_on_object", :reason => 'closed', :thing => 'contract')}") if issue.deliverable.contract.closed?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module ClassMethods
|
||||||
|
end
|
||||||
|
|
||||||
|
module InstanceMethods
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -54,6 +54,133 @@ class ContractsEditTest < ActionController::IntegrationTest
|
|||||||
assert_template 'contracts/show'
|
assert_template 'contracts/show'
|
||||||
|
|
||||||
assert_equal "An updated name", @contract.reload.name
|
assert_equal "An updated name", @contract.reload.name
|
||||||
|
end
|
||||||
|
|
||||||
|
context "locked contract" do
|
||||||
|
setup do
|
||||||
|
assert @contract.lock!
|
||||||
|
end
|
||||||
|
|
||||||
|
should "block edits" do
|
||||||
|
visit_contract_page(@contract)
|
||||||
|
click_link 'Update'
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
fill_in "Name", :with => 'An updated name'
|
||||||
|
click_button 'Save Contract'
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'contracts/edit'
|
||||||
|
|
||||||
|
assert_not_equal "An updated name", @contract.reload.name
|
||||||
|
end
|
||||||
|
|
||||||
|
should "block edits even when the status is changed to closed" do
|
||||||
|
visit_contract_page(@contract)
|
||||||
|
click_link 'Update'
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
fill_in "Name", :with => 'An updated name'
|
||||||
|
select "Closed", :from => "Status"
|
||||||
|
click_button 'Save Contract'
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'contracts/edit'
|
||||||
|
|
||||||
|
assert_not_equal "An updated name", @contract.reload.name
|
||||||
|
assert @contract.reload.locked?
|
||||||
|
end
|
||||||
|
|
||||||
|
should "be allowed to change the status from locked to open" do
|
||||||
|
visit_contract_page(@contract)
|
||||||
|
click_link 'Update'
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
select "Open", :from => "Status"
|
||||||
|
click_button 'Save Contract'
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'contracts/show'
|
||||||
|
|
||||||
|
assert @contract.reload.open?
|
||||||
|
end
|
||||||
|
|
||||||
|
should "be allowed to change the status from locked to closed" do
|
||||||
|
visit_contract_page(@contract)
|
||||||
|
click_link 'Update'
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
select "Closed", :from => "Status"
|
||||||
|
click_button 'Save Contract'
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'contracts/show'
|
||||||
|
|
||||||
|
assert @contract.reload.closed?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "closed contract" do
|
||||||
|
setup do
|
||||||
|
assert @contract.close!
|
||||||
|
end
|
||||||
|
|
||||||
|
should "block edits" do
|
||||||
|
visit_contract_page(@contract)
|
||||||
|
click_link 'Update'
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
fill_in "Name", :with => 'An updated name'
|
||||||
|
click_button 'Save Contract'
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'contracts/edit'
|
||||||
|
|
||||||
|
assert_not_equal "An updated name", @contract.reload.name
|
||||||
|
end
|
||||||
|
|
||||||
|
should "block edits weven when the status is changed to locked" do
|
||||||
|
visit_contract_page(@contract)
|
||||||
|
click_link 'Update'
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
fill_in "Name", :with => 'An updated name'
|
||||||
|
select "Locked", :from => "Status"
|
||||||
|
click_button 'Save Contract'
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'contracts/edit'
|
||||||
|
|
||||||
|
assert_not_equal "An updated name", @contract.reload.name
|
||||||
|
assert @contract.reload.closed?
|
||||||
|
end
|
||||||
|
|
||||||
|
should "be allowed to change the status from closed to open" do
|
||||||
|
visit_contract_page(@contract)
|
||||||
|
click_link 'Update'
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
select "Open", :from => "Status"
|
||||||
|
click_button 'Save Contract'
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'contracts/show'
|
||||||
|
|
||||||
|
assert @contract.reload.open?
|
||||||
|
end
|
||||||
|
|
||||||
|
should "be allowed to change the status from closed to locked" do
|
||||||
|
visit_contract_page(@contract)
|
||||||
|
click_link 'Update'
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
select "Locked", :from => "Status"
|
||||||
|
click_button 'Save Contract'
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'contracts/show'
|
||||||
|
|
||||||
|
assert @contract.reload.locked?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -5,8 +5,10 @@ class ContractsListTest < ActionController::IntegrationTest
|
|||||||
|
|
||||||
def setup
|
def setup
|
||||||
@project = Project.generate!(:identifier => 'main')
|
@project = Project.generate!(:identifier => 'main')
|
||||||
@contract = Contract.generate!(:project => @project)
|
@contract = Contract.generate!(:project => @project, :name => 'Contract1').reload
|
||||||
@contract2 = Contract.generate!(:project => @project)
|
@contract2 = Contract.generate!(:project => @project, :name => 'Contract2').reload
|
||||||
|
@contract_locked = Contract.generate!(:project => @project, :status => 'locked', :name => 'LockedContract').reload
|
||||||
|
@contract_closed = Contract.generate!(:project => @project, :status => 'closed', :name => 'ClosedContract').reload
|
||||||
|
|
||||||
@other_project = Project.generate!(:identifier => 'other')
|
@other_project = Project.generate!(:identifier => 'other')
|
||||||
@other_contract = Contract.generate!(:project => @other_project)
|
@other_contract = Contract.generate!(:project => @other_project)
|
||||||
@@ -44,10 +46,10 @@ class ContractsListTest < ActionController::IntegrationTest
|
|||||||
visit_contracts_for_project(@project)
|
visit_contracts_for_project(@project)
|
||||||
end
|
end
|
||||||
|
|
||||||
should "list all contracts for the project" do
|
should "list all contracts for the project grouped by status" do
|
||||||
visit_contracts_for_project(@project)
|
visit_contracts_for_project(@project)
|
||||||
|
|
||||||
assert_select "table#contracts" do
|
assert_select "table#contracts.open" do
|
||||||
[@contract, @contract2].each do |contract|
|
[@contract, @contract2].each do |contract|
|
||||||
assert_select "td.id", :text => /#{contract.id}/
|
assert_select "td.id", :text => /#{contract.id}/
|
||||||
assert_select "td.name", :text => /#{contract.name}/
|
assert_select "td.name", :text => /#{contract.name}/
|
||||||
@@ -56,7 +58,23 @@ class ContractsListTest < ActionController::IntegrationTest
|
|||||||
assert_select "td.total-budget"
|
assert_select "td.total-budget"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
assert_select "table#contracts.locked" do
|
||||||
|
assert_select "td.id", :text => /#{@contract_locked.id}/
|
||||||
|
assert_select "td.name", :text => /#{@contract_locked.name}/
|
||||||
|
assert_select "td.account-executive", :text => /#{@contract_locked.account_executive.name}/
|
||||||
|
assert_select "td.end-date", :text => /#{format_date(@contract_locked.end_date)}/
|
||||||
|
assert_select "td.total-budget"
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_select "table#contracts.closed" do
|
||||||
|
assert_select "td.id", :text => /#{@contract_closed.id}/
|
||||||
|
assert_select "td.name", :text => /#{@contract_closed.name}/
|
||||||
|
assert_select "td.account-executive", :text => /#{@contract_closed.account_executive.name}/
|
||||||
|
assert_select "td.end-date", :text => /#{format_date(@contract_closed.end_date)}/
|
||||||
|
assert_select "td.total-budget"
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
should "not list contracts from other projects" do
|
should "not list contracts from other projects" do
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ class ContractsNewTest < ActionController::IntegrationTest
|
|||||||
fill_in "Start", :with => '2010-01-01'
|
fill_in "Start", :with => '2010-01-01'
|
||||||
fill_in "End Date", :with => '2010-12-31'
|
fill_in "End Date", :with => '2010-12-31'
|
||||||
select "Net 30", :from => "Payment Terms"
|
select "Net 30", :from => "Payment Terms"
|
||||||
|
select "Locked", :from => "Status"
|
||||||
|
|
||||||
click_button "Save Contract"
|
click_button "Save Contract"
|
||||||
|
|
||||||
@@ -64,6 +65,7 @@ class ContractsNewTest < ActionController::IntegrationTest
|
|||||||
assert_equal '2010-01-01', @contract.start_date.to_s
|
assert_equal '2010-01-01', @contract.start_date.to_s
|
||||||
assert_equal '2010-12-31', @contract.end_date.to_s
|
assert_equal '2010-12-31', @contract.end_date.to_s
|
||||||
assert_equal 'Net 30', @contract.payment_term.name
|
assert_equal 'Net 30', @contract.payment_term.name
|
||||||
|
assert_equal "locked", @contract.status
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -9,7 +9,7 @@ class DeliverablesEditTest < ActionController::IntegrationTest
|
|||||||
@manager = User.generate!
|
@manager = User.generate!
|
||||||
@role = Role.generate!
|
@role = Role.generate!
|
||||||
User.add_to_project(@manager, @project, @role)
|
User.add_to_project(@manager, @project, @role)
|
||||||
@fixed_deliverable = FixedDeliverable.generate!(:contract => @contract, :manager => @manager, :title => 'The Title')
|
@fixed_deliverable = FixedDeliverable.generate!(:contract => @contract, :manager => @manager, :title => 'The Title', :notes => "", :feature_sign_off => false, :warranty_sign_off => false)
|
||||||
@hourly_deliverable = HourlyDeliverable.generate!(:contract => @contract, :manager => @manager, :title => 'An Hourly')
|
@hourly_deliverable = HourlyDeliverable.generate!(:contract => @contract, :manager => @manager, :title => 'An Hourly')
|
||||||
|
|
||||||
@user = User.generate_user_with_permission_to_manage_budget(:project => @project)
|
@user = User.generate_user_with_permission_to_manage_budget(:project => @project)
|
||||||
@@ -49,6 +49,7 @@ class DeliverablesEditTest < ActionController::IntegrationTest
|
|||||||
|
|
||||||
within("#deliverable-details") do
|
within("#deliverable-details") do
|
||||||
fill_in "Title", :with => 'An updated title'
|
fill_in "Title", :with => 'An updated title'
|
||||||
|
select "Locked", :from => "Status"
|
||||||
check "Feature Sign Off"
|
check "Feature Sign Off"
|
||||||
check "Warranty Sign Off"
|
check "Warranty Sign Off"
|
||||||
end
|
end
|
||||||
@@ -61,6 +62,7 @@ class DeliverablesEditTest < ActionController::IntegrationTest
|
|||||||
assert_equal "FixedDeliverable", @fixed_deliverable.reload.type
|
assert_equal "FixedDeliverable", @fixed_deliverable.reload.type
|
||||||
assert @fixed_deliverable.reload.warranty_sign_off?
|
assert @fixed_deliverable.reload.warranty_sign_off?
|
||||||
assert @fixed_deliverable.reload.feature_sign_off?
|
assert @fixed_deliverable.reload.feature_sign_off?
|
||||||
|
assert_equal "locked", @fixed_deliverable.reload.status
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -78,6 +80,7 @@ class DeliverablesEditTest < ActionController::IntegrationTest
|
|||||||
|
|
||||||
within("#deliverable-details") do
|
within("#deliverable-details") do
|
||||||
fill_in "Title", :with => 'An updated title'
|
fill_in "Title", :with => 'An updated title'
|
||||||
|
select "Locked", :from => "Status"
|
||||||
check "Feature Sign Off"
|
check "Feature Sign Off"
|
||||||
check "Warranty Sign Off"
|
check "Warranty Sign Off"
|
||||||
end
|
end
|
||||||
@@ -101,6 +104,7 @@ class DeliverablesEditTest < ActionController::IntegrationTest
|
|||||||
assert_equal "HourlyDeliverable", @hourly_deliverable.reload.type
|
assert_equal "HourlyDeliverable", @hourly_deliverable.reload.type
|
||||||
assert @hourly_deliverable.reload.warranty_sign_off?
|
assert @hourly_deliverable.reload.warranty_sign_off?
|
||||||
assert @hourly_deliverable.reload.feature_sign_off?
|
assert @hourly_deliverable.reload.feature_sign_off?
|
||||||
|
assert_equal "locked", @hourly_deliverable.reload.status
|
||||||
|
|
||||||
assert_equal 1, @hourly_deliverable.labor_budgets.count
|
assert_equal 1, @hourly_deliverable.labor_budgets.count
|
||||||
@labor_budget = @hourly_deliverable.labor_budgets.first
|
@labor_budget = @hourly_deliverable.labor_budgets.first
|
||||||
@@ -471,4 +475,240 @@ class DeliverablesEditTest < ActionController::IntegrationTest
|
|||||||
assert_equal 3, @retainer_deliverable.fixed_budgets.count
|
assert_equal 3, @retainer_deliverable.fixed_budgets.count
|
||||||
assert_equal [600, nil, nil], @retainer_deliverable.fixed_budgets.collect(&:budget)
|
assert_equal [600, nil, nil], @retainer_deliverable.fixed_budgets.collect(&:budget)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "locked deliverable" do
|
||||||
|
setup do
|
||||||
|
assert @fixed_deliverable.lock!
|
||||||
|
end
|
||||||
|
|
||||||
|
should "block edits to locked deliverables" do
|
||||||
|
visit_contract_page(@contract)
|
||||||
|
click_link_within "#deliverable_details_#{@fixed_deliverable.id}", 'Edit'
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
within("#deliverable-details") do
|
||||||
|
fill_in "Title", :with => 'An updated title'
|
||||||
|
end
|
||||||
|
|
||||||
|
click_button "Save"
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'deliverables/edit'
|
||||||
|
|
||||||
|
assert_not_equal "An updated title", @fixed_deliverable.reload.title
|
||||||
|
end
|
||||||
|
|
||||||
|
should "block edits to locked deliverables even when status changes to closed" do
|
||||||
|
visit_contract_page(@contract)
|
||||||
|
click_link_within "#deliverable_details_#{@fixed_deliverable.id}", 'Edit'
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
within("#deliverable-details") do
|
||||||
|
fill_in "Title", :with => 'An updated title'
|
||||||
|
select "Closed", :from => "Status"
|
||||||
|
end
|
||||||
|
|
||||||
|
click_button "Save"
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'deliverables/edit'
|
||||||
|
|
||||||
|
assert_not_equal "An updated title", @fixed_deliverable.reload.title
|
||||||
|
assert @fixed_deliverable.reload.locked?
|
||||||
|
end
|
||||||
|
|
||||||
|
should "be allowed to change the status on a locked deliverables to open" do
|
||||||
|
visit_contract_page(@contract)
|
||||||
|
click_link_within "#deliverable_details_#{@fixed_deliverable.id}", 'Edit'
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
within("#deliverable-details") do
|
||||||
|
select "Open", :from => "Status"
|
||||||
|
end
|
||||||
|
|
||||||
|
click_button "Save"
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'contracts/show'
|
||||||
|
|
||||||
|
assert @fixed_deliverable.reload.open?
|
||||||
|
end
|
||||||
|
|
||||||
|
should "be allowed to change the status on a locked deliverables to closed" do
|
||||||
|
visit_contract_page(@contract)
|
||||||
|
click_link_within "#deliverable_details_#{@fixed_deliverable.id}", 'Edit'
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
within("#deliverable-details") do
|
||||||
|
select "Closed", :from => "Status"
|
||||||
|
end
|
||||||
|
|
||||||
|
click_button "Save"
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'contracts/show'
|
||||||
|
|
||||||
|
assert @fixed_deliverable.reload.closed?
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
context "closed deliverable" do
|
||||||
|
setup do
|
||||||
|
assert @fixed_deliverable.close!
|
||||||
|
end
|
||||||
|
|
||||||
|
should "block edits to closed deliverables" do
|
||||||
|
visit_contract_page(@contract)
|
||||||
|
click_link_within "#deliverable_details_#{@fixed_deliverable.id}", 'Edit'
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
within("#deliverable-details") do
|
||||||
|
fill_in "Title", :with => 'An updated title'
|
||||||
|
end
|
||||||
|
|
||||||
|
click_button "Save"
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'deliverables/edit'
|
||||||
|
|
||||||
|
assert_not_equal "An updated title", @fixed_deliverable.reload.title
|
||||||
|
end
|
||||||
|
|
||||||
|
should "block edits to closed deliverables even when the status is changed to locked" do
|
||||||
|
visit_contract_page(@contract)
|
||||||
|
click_link_within "#deliverable_details_#{@fixed_deliverable.id}", 'Edit'
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
within("#deliverable-details") do
|
||||||
|
fill_in "Title", :with => 'An updated title'
|
||||||
|
select "Locked", :from => "Status"
|
||||||
|
end
|
||||||
|
|
||||||
|
click_button "Save"
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'deliverables/edit'
|
||||||
|
|
||||||
|
assert_not_equal "An updated title", @fixed_deliverable.reload.title
|
||||||
|
assert @fixed_deliverable.reload.closed?
|
||||||
|
end
|
||||||
|
|
||||||
|
should "be allowed to change the status on a closed deliverables to open" do
|
||||||
|
visit_contract_page(@contract)
|
||||||
|
click_link_within "#deliverable_details_#{@fixed_deliverable.id}", 'Edit'
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
within("#deliverable-details") do
|
||||||
|
select "Open", :from => "Status"
|
||||||
|
end
|
||||||
|
|
||||||
|
click_button "Save"
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'contracts/show'
|
||||||
|
|
||||||
|
assert @fixed_deliverable.reload.open?
|
||||||
|
end
|
||||||
|
|
||||||
|
should "be allowed to change the status on a closed deliverables to Locked" do
|
||||||
|
visit_contract_page(@contract)
|
||||||
|
click_link_within "#deliverable_details_#{@fixed_deliverable.id}", 'Edit'
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
within("#deliverable-details") do
|
||||||
|
select "Locked", :from => "Status"
|
||||||
|
end
|
||||||
|
|
||||||
|
click_button "Save"
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'contracts/show'
|
||||||
|
|
||||||
|
assert @fixed_deliverable.reload.locked?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "a Deliverable on a locked Contract" do
|
||||||
|
setup do
|
||||||
|
assert @contract.lock!
|
||||||
|
end
|
||||||
|
|
||||||
|
should "be blocked from editing" do
|
||||||
|
visit_contract_page(@contract)
|
||||||
|
click_link_within "#deliverable_details_#{@fixed_deliverable.id}", 'Edit'
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
within("#deliverable-details") do
|
||||||
|
fill_in "Title", :with => 'An updated title'
|
||||||
|
end
|
||||||
|
|
||||||
|
click_button "Save"
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'deliverables/edit'
|
||||||
|
|
||||||
|
assert_not_equal "An updated title", @fixed_deliverable.reload.title
|
||||||
|
end
|
||||||
|
|
||||||
|
should "allow status only changes" do
|
||||||
|
visit_contract_page(@contract)
|
||||||
|
click_link_within "#deliverable_details_#{@fixed_deliverable.id}", 'Edit'
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
within("#deliverable-details") do
|
||||||
|
select "Locked", :from => "Status"
|
||||||
|
end
|
||||||
|
|
||||||
|
click_button "Save"
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'contracts/show'
|
||||||
|
|
||||||
|
assert @fixed_deliverable.reload.locked?
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
context "a Deliverable on a closed Contract" do
|
||||||
|
setup do
|
||||||
|
assert @contract.close!
|
||||||
|
end
|
||||||
|
|
||||||
|
should "be blocked from editing" do
|
||||||
|
visit_contract_page(@contract)
|
||||||
|
click_link_within "#deliverable_details_#{@fixed_deliverable.id}", 'Edit'
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
within("#deliverable-details") do
|
||||||
|
fill_in "Title", :with => 'An updated title'
|
||||||
|
end
|
||||||
|
|
||||||
|
click_button "Save"
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'deliverables/edit'
|
||||||
|
|
||||||
|
assert_not_equal "An updated title", @fixed_deliverable.reload.title
|
||||||
|
end
|
||||||
|
|
||||||
|
should "allow status only changes" do
|
||||||
|
visit_contract_page(@contract)
|
||||||
|
click_link_within "#deliverable_details_#{@fixed_deliverable.id}", 'Edit'
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
within("#deliverable-details") do
|
||||||
|
select "Locked", :from => "Status"
|
||||||
|
end
|
||||||
|
|
||||||
|
click_button "Save"
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'contracts/show'
|
||||||
|
|
||||||
|
assert @fixed_deliverable.reload.locked?
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -74,6 +74,7 @@ class DeliverablesNewTest < ActionController::IntegrationTest
|
|||||||
within("#deliverable-details") do
|
within("#deliverable-details") do
|
||||||
fill_in "Title", :with => 'A New Deliverable'
|
fill_in "Title", :with => 'A New Deliverable'
|
||||||
select "Fixed", :from => "Type"
|
select "Fixed", :from => "Type"
|
||||||
|
select "Locked", :from => "Status"
|
||||||
select @manager.name, :from => "Manager"
|
select @manager.name, :from => "Manager"
|
||||||
fill_in "Start", :with => '2010-01-01'
|
fill_in "Start", :with => '2010-01-01'
|
||||||
fill_in "End Date", :with => '2010-12-31'
|
fill_in "End Date", :with => '2010-12-31'
|
||||||
@@ -95,6 +96,7 @@ class DeliverablesNewTest < ActionController::IntegrationTest
|
|||||||
assert_equal '2010-12-31', @deliverable.end_date.to_s
|
assert_equal '2010-12-31', @deliverable.end_date.to_s
|
||||||
assert_equal @manager, @deliverable.manager
|
assert_equal @manager, @deliverable.manager
|
||||||
assert_equal 1000.0, @deliverable.total.to_f
|
assert_equal 1000.0, @deliverable.total.to_f
|
||||||
|
assert_equal "locked", @deliverable.status
|
||||||
end
|
end
|
||||||
|
|
||||||
should "create a new Hourly deliverable" do
|
should "create a new Hourly deliverable" do
|
||||||
@@ -109,6 +111,7 @@ class DeliverablesNewTest < ActionController::IntegrationTest
|
|||||||
within("#deliverable-details") do
|
within("#deliverable-details") do
|
||||||
fill_in "Title", :with => 'A New Deliverable'
|
fill_in "Title", :with => 'A New Deliverable'
|
||||||
select "Hourly", :from => "Type"
|
select "Hourly", :from => "Type"
|
||||||
|
select "Locked", :from => "Status"
|
||||||
select @manager.name, :from => "Manager"
|
select @manager.name, :from => "Manager"
|
||||||
fill_in "Start", :with => '2010-01-01'
|
fill_in "Start", :with => '2010-01-01'
|
||||||
fill_in "End Date", :with => '2010-12-31'
|
fill_in "End Date", :with => '2010-12-31'
|
||||||
@@ -128,7 +131,8 @@ class DeliverablesNewTest < ActionController::IntegrationTest
|
|||||||
assert_equal '2010-01-01', @deliverable.start_date.to_s
|
assert_equal '2010-01-01', @deliverable.start_date.to_s
|
||||||
assert_equal '2010-12-31', @deliverable.end_date.to_s
|
assert_equal '2010-12-31', @deliverable.end_date.to_s
|
||||||
assert_equal @manager, @deliverable.manager
|
assert_equal @manager, @deliverable.manager
|
||||||
|
assert_equal "locked", @deliverable.status
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
should "create a new Retainer deliverable" do
|
should "create a new Retainer deliverable" do
|
||||||
@@ -143,6 +147,7 @@ class DeliverablesNewTest < ActionController::IntegrationTest
|
|||||||
within("#deliverable-details") do
|
within("#deliverable-details") do
|
||||||
fill_in "Title", :with => 'A New Deliverable'
|
fill_in "Title", :with => 'A New Deliverable'
|
||||||
select "Retainer", :from => "Type"
|
select "Retainer", :from => "Type"
|
||||||
|
select "Locked", :from => "Status"
|
||||||
select @manager.name, :from => "Manager"
|
select @manager.name, :from => "Manager"
|
||||||
fill_in "Start", :with => '2010-01-01'
|
fill_in "Start", :with => '2010-01-01'
|
||||||
fill_in "End Date", :with => '2010-12-31'
|
fill_in "End Date", :with => '2010-12-31'
|
||||||
@@ -171,7 +176,8 @@ class DeliverablesNewTest < ActionController::IntegrationTest
|
|||||||
assert_equal '2010-01-01', @deliverable.start_date.to_s
|
assert_equal '2010-01-01', @deliverable.start_date.to_s
|
||||||
assert_equal '2010-12-31', @deliverable.end_date.to_s
|
assert_equal '2010-12-31', @deliverable.end_date.to_s
|
||||||
assert_equal @manager, @deliverable.manager
|
assert_equal @manager, @deliverable.manager
|
||||||
|
assert_equal "locked", @deliverable.status
|
||||||
|
|
||||||
# Budget items, one per month
|
# Budget items, one per month
|
||||||
labor_budgets = @deliverable.labor_budgets
|
labor_budgets = @deliverable.labor_budgets
|
||||||
assert_equal 12, labor_budgets.length
|
assert_equal 12, labor_budgets.length
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ class RedmineContracts::Hooks::ControllerIssuesEditBeforeSaveTest < ActionContro
|
|||||||
context "for a new issue" do
|
context "for a new issue" do
|
||||||
setup do
|
setup do
|
||||||
visit_project(@project)
|
visit_project(@project)
|
||||||
click_link "New issue"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
should "set the issue's deliverable" do
|
should "set the issue's deliverable" do
|
||||||
|
click_link "New issue"
|
||||||
fill_in "Subject", :with => 'Hook test'
|
fill_in "Subject", :with => 'Hook test'
|
||||||
select @deliverable2.title, :from => "Deliverable"
|
select @deliverable2.title, :from => "Deliverable"
|
||||||
click_button "Create"
|
click_button "Create"
|
||||||
@@ -38,6 +38,70 @@ class RedmineContracts::Hooks::ControllerIssuesEditBeforeSaveTest < ActionContro
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
should "not allow setting a locked Deliverable" do
|
||||||
|
assert @deliverable2.lock!
|
||||||
|
click_link "New issue"
|
||||||
|
|
||||||
|
fill_in "Subject", :with => 'Hook test'
|
||||||
|
select @deliverable2.title, :from => "Deliverable"
|
||||||
|
assert_no_difference("Issue.count") do
|
||||||
|
click_button "Create"
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal nil, Issue.last.deliverable
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
should "not allow setting a closed Deliverable" do
|
||||||
|
assert @deliverable2.close!
|
||||||
|
click_link "New issue"
|
||||||
|
|
||||||
|
fill_in "Subject", :with => 'Hook test'
|
||||||
|
select @deliverable2.title, :from => "Deliverable"
|
||||||
|
assert_no_difference("Issue.count") do
|
||||||
|
click_button "Create"
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal nil, Issue.last.deliverable
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
should "not allow setting a Deliverable on a locked Contract" do
|
||||||
|
assert @contract2.lock!
|
||||||
|
click_link "New issue"
|
||||||
|
|
||||||
|
fill_in "Subject", :with => 'Hook test'
|
||||||
|
select @deliverable2.title, :from => "Deliverable"
|
||||||
|
assert_no_difference("Issue.count") do
|
||||||
|
click_button "Create"
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal nil, Issue.last.deliverable
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
should "not allow setting a Deliverable on a closed Contract" do
|
||||||
|
assert @contract2.close!
|
||||||
|
click_link "New issue"
|
||||||
|
|
||||||
|
fill_in "Subject", :with => 'Hook test'
|
||||||
|
select @deliverable2.title, :from => "Deliverable"
|
||||||
|
assert_no_difference("Issue.count") do
|
||||||
|
click_button "Create"
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal nil, Issue.last.deliverable
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
context "with no permission to Assign Deliverable" do
|
context "with no permission to Assign Deliverable" do
|
||||||
should "not allow setting the Deliverable (force HTTP request)" do
|
should "not allow setting the Deliverable (force HTTP request)" do
|
||||||
@role.permissions.delete(:assign_deliverable_to_issue)
|
@role.permissions.delete(:assign_deliverable_to_issue)
|
||||||
@@ -69,6 +133,75 @@ class RedmineContracts::Hooks::ControllerIssuesEditBeforeSaveTest < ActionContro
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
should "not allow updating to a locked deliverable" do
|
||||||
|
assert @deliverable2.lock!
|
||||||
|
select @deliverable2.title, :from => "Deliverable"
|
||||||
|
click_button "Submit"
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
@issue.reload
|
||||||
|
assert_equal nil, @issue.deliverable
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
should "not allow updating to a closed deliverable" do
|
||||||
|
assert @deliverable2.close!
|
||||||
|
select @deliverable2.title, :from => "Deliverable"
|
||||||
|
click_button "Submit"
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
@issue.reload
|
||||||
|
assert_equal nil, @issue.deliverable
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
should "not allow updating to a deliverable on a locked contract" do
|
||||||
|
assert @contract2.lock!
|
||||||
|
select @deliverable2.title, :from => "Deliverable"
|
||||||
|
click_button "Submit"
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
@issue.reload
|
||||||
|
assert_equal nil, @issue.deliverable
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
should "not allow updating to a deliverable on a closed contract" do
|
||||||
|
assert @contract2.close!
|
||||||
|
select @deliverable2.title, :from => "Deliverable"
|
||||||
|
click_button "Submit"
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
@issue.reload
|
||||||
|
assert_equal nil, @issue.deliverable
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
should "allow updating an issue, even if the deliverable is locked as long as the deliverable isn't changed" do
|
||||||
|
select @deliverable2.title, :from => "Deliverable"
|
||||||
|
click_button "Submit"
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
@issue.reload
|
||||||
|
assert_equal @deliverable2, @issue.deliverable
|
||||||
|
|
||||||
|
# Now normal update after locking
|
||||||
|
assert @deliverable2.lock!
|
||||||
|
fill_in "Subject", :with => 'Change subject'
|
||||||
|
click_button "Submit"
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
@issue.reload
|
||||||
|
assert_equal "Change subject", @issue.subject
|
||||||
|
assert_equal @deliverable2, @issue.deliverable
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
context "with no permission to Assign Deliverable" do
|
context "with no permission to Assign Deliverable" do
|
||||||
should "not allow setting the Deliverable (force HTTP request)" do
|
should "not allow setting the Deliverable (force HTTP request)" do
|
||||||
@role.permissions.delete(:assign_deliverable_to_issue)
|
@role.permissions.delete(:assign_deliverable_to_issue)
|
||||||
|
|||||||
+3
-3
@@ -19,15 +19,15 @@ class RedmineContracts::Hooks::HelperIssuesShowDetailAfterSettingHookTest < Acti
|
|||||||
# Set first
|
# Set first
|
||||||
@issue.init_journal(@manager)
|
@issue.init_journal(@manager)
|
||||||
@issue.deliverable = @deliverable1
|
@issue.deliverable = @deliverable1
|
||||||
@issue.save!
|
@issue.save! && @issue.reload
|
||||||
# Change
|
# Change
|
||||||
@issue.init_journal(@manager)
|
@issue.init_journal(@manager)
|
||||||
@issue.deliverable = @deliverable2
|
@issue.deliverable = @deliverable2
|
||||||
@issue.save!
|
@issue.save! && @issue.reload
|
||||||
# Unset
|
# Unset
|
||||||
@issue.init_journal(@manager)
|
@issue.init_journal(@manager)
|
||||||
@issue.deliverable = nil
|
@issue.deliverable = nil
|
||||||
@issue.save!
|
@issue.save! && @issue.reload
|
||||||
|
|
||||||
login_as('manager', 'existing')
|
login_as('manager', 'existing')
|
||||||
|
|
||||||
|
|||||||
+40
@@ -11,14 +11,25 @@ class RedmineContracts::Hooks::ViewIssuesBulkEditDetailsBottomHookTest < ActionC
|
|||||||
@issue3 = Issue.generate_for_project!(@project)
|
@issue3 = Issue.generate_for_project!(@project)
|
||||||
@contract1 = Contract.generate!(:project => @project)
|
@contract1 = Contract.generate!(:project => @project)
|
||||||
@contract2 = Contract.generate!(:project => @project)
|
@contract2 = Contract.generate!(:project => @project)
|
||||||
|
@locked_contract = Contract.generate!(:project => @project)
|
||||||
|
@closed_contract = Contract.generate!(:project => @project)
|
||||||
|
|
||||||
@manager = User.generate!(:login => 'manager', :password => 'existing', :password_confirmation => 'existing')
|
@manager = User.generate!(:login => 'manager', :password => 'existing', :password_confirmation => 'existing')
|
||||||
@role = Role.generate!(:permissions => [:view_issues, :edit_issues])
|
@role = Role.generate!(:permissions => [:view_issues, :edit_issues])
|
||||||
User.add_to_project(@manager, @project, @role)
|
User.add_to_project(@manager, @project, @role)
|
||||||
@deliverable1 = FixedDeliverable.generate!(:contract => @contract1, :manager => @manager, :title => 'The Title')
|
@deliverable1 = FixedDeliverable.generate!(:contract => @contract1, :manager => @manager, :title => 'The Title')
|
||||||
@deliverable2 = FixedDeliverable.generate!(:contract => @contract2, :manager => @manager, :title => 'The Title')
|
@deliverable2 = FixedDeliverable.generate!(:contract => @contract2, :manager => @manager, :title => 'The Title')
|
||||||
|
@locked_deliverable = FixedDeliverable.generate!(:contract => @contract1, :manager => @manager, :title => 'Locked Deliverable', :status => 'locked')
|
||||||
|
@closed_deliverable = FixedDeliverable.generate!(:contract => @contract1, :manager => @manager, :title => 'Closed Deliverable', :status => 'closed')
|
||||||
|
@deliverable1_on_locked_contract = FixedDeliverable.generate!(:contract => @locked_contract, :manager => @manager, :title => 'Deliverable 1 on locked contract')
|
||||||
|
@deliverable2_on_locked_contract = FixedDeliverable.generate!(:contract => @locked_contract, :manager => @manager, :title => 'Deliverable 2 on locked contract')
|
||||||
|
@deliverable_on_closed_contract = FixedDeliverable.generate!(:contract => @closed_contract, :manager => @manager, :title => 'Deliverable on closed contract')
|
||||||
@issue.deliverable = @deliverable1
|
@issue.deliverable = @deliverable1
|
||||||
|
|
||||||
|
# Set contract statuses now that all deliverables are created
|
||||||
|
assert @locked_contract.lock!
|
||||||
|
assert @closed_contract.close!
|
||||||
|
|
||||||
login_as('manager', 'existing')
|
login_as('manager', 'existing')
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -42,6 +53,35 @@ class RedmineContracts::Hooks::ViewIssuesBulkEditDetailsBottomHookTest < ActionC
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
should "disable all locked deliverables" do
|
||||||
|
assert_select "select#deliverable_id" do
|
||||||
|
assert_select "option[disabled=disabled]", :text => /#{@locked_deliverable.title}/
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
should "disable all deliverables on locked contracts" do
|
||||||
|
assert_select "select#deliverable_id" do
|
||||||
|
assert_select "optgroup[label=?]", @locked_contract.name do
|
||||||
|
assert_select "option[disabled=disabled]", :text => /#{@deliverable1_on_locked_contract.title}/
|
||||||
|
assert_select "option[disabled=disabled]", :text => /#{@deliverable2_on_locked_contract.title}/
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
should "not show closed deliverables" do
|
||||||
|
assert_select "select#deliverable_id" do
|
||||||
|
assert_select "option", :text => /#{@closed_deliverable.title}/, :count => 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
should "not show deliverables on closed contracts" do
|
||||||
|
assert_select "select#deliverable_id" do
|
||||||
|
assert_select "optgroup[label=?]", @closed_contract.name, :count => 0
|
||||||
|
assert_select "option", :text => /#{@deliverable_on_closed_contract.title}/, :count => 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with no permission to Assign Deliverable" do
|
context "with no permission to Assign Deliverable" do
|
||||||
|
|||||||
+86
-2
@@ -9,13 +9,25 @@ class RedmineContracts::Hooks::ViewIssuesFormDetailsBottomTest < ActionControlle
|
|||||||
@issue = Issue.generate_for_project!(@project)
|
@issue = Issue.generate_for_project!(@project)
|
||||||
@contract1 = Contract.generate!(:project => @project)
|
@contract1 = Contract.generate!(:project => @project)
|
||||||
@contract2 = Contract.generate!(:project => @project)
|
@contract2 = Contract.generate!(:project => @project)
|
||||||
|
@locked_contract = Contract.generate!(:project => @project)
|
||||||
|
@closed_contract = Contract.generate!(:project => @project)
|
||||||
|
|
||||||
@manager = User.generate!(:login => 'manager', :password => 'existing', :password_confirmation => 'existing')
|
@manager = User.generate!(:login => 'manager', :password => 'existing', :password_confirmation => 'existing')
|
||||||
@role = Role.generate!(:permissions => [:view_issues, :edit_issues])
|
@role = Role.generate!(:permissions => [:view_issues, :edit_issues])
|
||||||
User.add_to_project(@manager, @project, @role)
|
User.add_to_project(@manager, @project, @role)
|
||||||
@deliverable1 = FixedDeliverable.generate!(:contract => @contract1, :manager => @manager, :title => 'The Title')
|
@deliverable1 = FixedDeliverable.generate!(:contract => @contract1, :manager => @manager, :title => 'Deliverable1')
|
||||||
@deliverable2 = FixedDeliverable.generate!(:contract => @contract2, :manager => @manager, :title => 'The Title')
|
@deliverable2 = FixedDeliverable.generate!(:contract => @contract2, :manager => @manager, :title => 'Deliverable2')
|
||||||
|
@locked_deliverable = FixedDeliverable.generate!(:contract => @contract1, :manager => @manager, :title => 'Locked Deliverable', :status => 'locked')
|
||||||
|
@closed_deliverable = FixedDeliverable.generate!(:contract => @contract1, :manager => @manager, :title => 'Closed Deliverable', :status => 'closed')
|
||||||
|
@deliverable1_on_locked_contract = FixedDeliverable.generate!(:contract => @locked_contract, :manager => @manager, :title => 'Deliverable 1 on locked contract')
|
||||||
|
@deliverable2_on_locked_contract = FixedDeliverable.generate!(:contract => @locked_contract, :manager => @manager, :title => 'Deliverable 2 on locked contract')
|
||||||
|
@deliverable_on_closed_contract = FixedDeliverable.generate!(:contract => @closed_contract, :manager => @manager, :title => 'Deliverable on closed contract')
|
||||||
@issue.deliverable = @deliverable1
|
@issue.deliverable = @deliverable1
|
||||||
|
assert @issue.save
|
||||||
|
|
||||||
|
# Set contract statuses now that all deliverables are created
|
||||||
|
assert @locked_contract.lock!
|
||||||
|
assert @closed_contract.close!
|
||||||
|
|
||||||
login_as('manager', 'existing')
|
login_as('manager', 'existing')
|
||||||
end
|
end
|
||||||
@@ -39,6 +51,78 @@ class RedmineContracts::Hooks::ViewIssuesFormDetailsBottomTest < ActionControlle
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
should "disable all locked deliverables" do
|
||||||
|
assert_select "select#issue_deliverable_id" do
|
||||||
|
assert_select "option[disabled=disabled]", :text => /#{@locked_deliverable.title}/
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
should "disable all deliverables on locked contracts" do
|
||||||
|
assert_select "select#issue_deliverable_id" do
|
||||||
|
assert_select "optgroup[label=?]", @locked_contract.name do
|
||||||
|
assert_select "option[disabled=disabled]", :text => /#{@deliverable1_on_locked_contract.title}/
|
||||||
|
assert_select "option[disabled=disabled]", :text => /#{@deliverable2_on_locked_contract.title}/
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
should "not show closed deliverables" do
|
||||||
|
assert_select "select#issue_deliverable_id" do
|
||||||
|
assert_select "option", :text => /#{@closed_deliverable.title}/, :count => 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
should "not show deliverables on closed contracts" do
|
||||||
|
assert_select "select#issue_deliverable_id" do
|
||||||
|
assert_select "optgroup[label=?]", @closed_contract.name, :count => 0
|
||||||
|
assert_select "option", :text => /#{@deliverable_on_closed_contract.title}/, :count => 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
should "show the assigned deliverable as an option, even if it's locked" do
|
||||||
|
@deliverable1.lock!
|
||||||
|
visit_issue_page(@issue)
|
||||||
|
|
||||||
|
assert_select "select#issue_deliverable_id" do
|
||||||
|
assert_select "option[disabled=disabled]", :text => /#{@deliverable1.title}/, :count => 0 # Not disabled
|
||||||
|
assert_select "option", :text => /#{@deliverable1.title}/, :count => 1 # Present
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
should "show the assigned deliverable as an option, even if it's closed" do
|
||||||
|
@deliverable1.close!
|
||||||
|
visit_issue_page(@issue)
|
||||||
|
|
||||||
|
assert_select "select#issue_deliverable_id" do
|
||||||
|
assert_select "option[disabled=disabled]", :text => /#{@deliverable1.title}/, :count => 0 # Not disabled
|
||||||
|
assert_select "option", :text => /#{@deliverable1.title}/, :count => 1 # Present
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
should "show the assigned deliverable as an option, even if it's contract is locked" do
|
||||||
|
@contract1.lock!
|
||||||
|
visit_issue_page(@issue)
|
||||||
|
|
||||||
|
assert_select "select#issue_deliverable_id" do
|
||||||
|
assert_select "option[disabled=disabled]", :text => /#{@deliverable1.title}/, :count => 0 # Not disabled
|
||||||
|
assert_select "option", :text => /#{@deliverable1.title}/, :count => 1 # Present
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
should "show the assigned deliverable as an option, even if it's contract is closed" do
|
||||||
|
@contract1.close!
|
||||||
|
visit_issue_page(@issue)
|
||||||
|
|
||||||
|
assert_select "select#issue_deliverable_id" do
|
||||||
|
assert_select "option[disabled=disabled]", :text => /#{@deliverable1.title}/, :count => 0 # Not disabled
|
||||||
|
assert_select "option", :text => /#{@deliverable1.title}/, :count => 1 # Present
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with no permission to Assign Deliverable" do
|
context "with no permission to Assign Deliverable" do
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ class ContractTest < ActiveSupport::TestCase
|
|||||||
should_allow_values_for :discount_type, "$", "%", nil, ''
|
should_allow_values_for :discount_type, "$", "%", nil, ''
|
||||||
should_not_allow_values_for :discount_type, ["amount", "percent", "bar"]
|
should_not_allow_values_for :discount_type, ["amount", "percent", "bar"]
|
||||||
|
|
||||||
|
should_allow_values_for :status, "", nil, 'open', 'locked', 'closed'
|
||||||
|
should_not_allow_values_for :status, "other", "things", "1"
|
||||||
|
|
||||||
context "end_date" do
|
context "end_date" do
|
||||||
should "be after start_date" do
|
should "be after start_date" do
|
||||||
@contract = Contract.new(:start_date => Date.today, :end_date => Date.yesterday)
|
@contract = Contract.new(:start_date => Date.today, :end_date => Date.yesterday)
|
||||||
@@ -32,6 +35,12 @@ class ContractTest < ActiveSupport::TestCase
|
|||||||
assert_equal false, @contract.executed
|
assert_equal false, @contract.executed
|
||||||
end
|
end
|
||||||
|
|
||||||
|
should "default status to open" do
|
||||||
|
@contract = Contract.new
|
||||||
|
|
||||||
|
assert_equal "open", @contract.status
|
||||||
|
end
|
||||||
|
|
||||||
context "#labor_budget" do
|
context "#labor_budget" do
|
||||||
should "sum all of the labor budgets of the Deliverables" do
|
should "sum all of the labor budgets of the Deliverables" do
|
||||||
contract = Contract.generate!
|
contract = Contract.generate!
|
||||||
|
|||||||
@@ -12,6 +12,13 @@ class DeliverableTest < ActiveSupport::TestCase
|
|||||||
should_validate_presence_of :type
|
should_validate_presence_of :type
|
||||||
should_validate_presence_of :manager
|
should_validate_presence_of :manager
|
||||||
|
|
||||||
|
should_allow_values_for :status, "", nil, 'open', 'locked', 'closed'
|
||||||
|
should_not_allow_values_for :status, "other", "things", "1"
|
||||||
|
|
||||||
|
should "default status to open" do
|
||||||
|
assert_equal "open", Deliverable.new.status
|
||||||
|
end
|
||||||
|
|
||||||
context "#total=" do
|
context "#total=" do
|
||||||
should "strip dollar signs when writing" do
|
should "strip dollar signs when writing" do
|
||||||
d = Deliverable.new
|
d = Deliverable.new
|
||||||
@@ -35,4 +42,45 @@ class DeliverableTest < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "with a locked contract" do
|
||||||
|
should "block creating a new deliverable" do
|
||||||
|
contract = Contract.generate!(:status => "locked")
|
||||||
|
deliverable = FixedDeliverable.spawn(:contract => contract)
|
||||||
|
|
||||||
|
assert !deliverable.valid?
|
||||||
|
assert deliverable.errors.on_base.include?("Can't create a deliverable on a locked contract")
|
||||||
|
end
|
||||||
|
|
||||||
|
should "block deleting a deliverable" do
|
||||||
|
contract = Contract.generate!
|
||||||
|
deliverable = FixedDeliverable.generate!(:contract => contract).reload
|
||||||
|
assert contract.lock!
|
||||||
|
|
||||||
|
assert_no_difference("Deliverable.count") do
|
||||||
|
deliverable.destroy
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with a closed contract" do
|
||||||
|
should "block creating a new deliverable" do
|
||||||
|
contract = Contract.generate!(:status => "closed")
|
||||||
|
deliverable = FixedDeliverable.spawn(:contract => contract)
|
||||||
|
|
||||||
|
assert !deliverable.valid?
|
||||||
|
assert deliverable.errors.on_base.include?("Can't create a deliverable on a closed contract")
|
||||||
|
end
|
||||||
|
|
||||||
|
should "block deleting a deliverable" do
|
||||||
|
contract = Contract.generate!
|
||||||
|
deliverable = FixedDeliverable.generate!(:contract => contract).reload
|
||||||
|
assert contract.close!
|
||||||
|
|
||||||
|
assert_no_difference("Deliverable.count") do
|
||||||
|
deliverable.destroy
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
@@ -19,6 +19,9 @@ class RedmineContracts::Hooks::ViewIssuesShowDetailsBottomTest < ActionControlle
|
|||||||
@controller ||= ApplicationController.new
|
@controller ||= ApplicationController.new
|
||||||
@controller.class.send(:include, ::Redmine::I18n)
|
@controller.class.send(:include, ::Redmine::I18n)
|
||||||
@controller.response ||= ActionController::TestResponse.new
|
@controller.response ||= ActionController::TestResponse.new
|
||||||
|
def @controller.api_request?
|
||||||
|
false
|
||||||
|
end
|
||||||
# Hack to support render_on
|
# Hack to support render_on
|
||||||
@controller.instance_variable_set('@template', template)
|
@controller.instance_variable_set('@template', template)
|
||||||
@controller.response = response
|
@controller.response = response
|
||||||
|
|||||||
@@ -0,0 +1,123 @@
|
|||||||
|
require File.dirname(__FILE__) + '/../../../../test_helper'
|
||||||
|
|
||||||
|
class RedmineContracts::Patches::TimeEntryTest < ActionController::TestCase
|
||||||
|
|
||||||
|
def setup
|
||||||
|
@project = Project.generate!
|
||||||
|
@contract = Contract.generate!(:project => @project, :status => 'open')
|
||||||
|
@deliverable = FixedDeliverable.generate!(:contract => @contract, :status => 'open').reload
|
||||||
|
@issue = Issue.generate_for_project!(@project, :deliverable => @deliverable).reload
|
||||||
|
assert_equal @deliverable, @issue.deliverable
|
||||||
|
@user = User.generate!
|
||||||
|
@role = Role.generate!
|
||||||
|
User.add_to_project(@user, @project, @role)
|
||||||
|
@activity = TimeEntryActivity.generate!
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_time_entry
|
||||||
|
@issue.reload
|
||||||
|
@time_entry = TimeEntry.create(:issue => @issue,
|
||||||
|
:project => @project,
|
||||||
|
:spent_on => Date.today,
|
||||||
|
:activity => @activity,
|
||||||
|
:hours => 10,
|
||||||
|
:user => @user)
|
||||||
|
end
|
||||||
|
|
||||||
|
def assert_error_about_locked_deliverable(time_entry)
|
||||||
|
assert_equal "Can't create a time entry on a locked deliverable", time_entry.errors.on_base
|
||||||
|
end
|
||||||
|
|
||||||
|
def assert_error_about_locked_contract(time_entry)
|
||||||
|
assert_equal "Can't create a time entry on a locked contract", time_entry.errors.on_base
|
||||||
|
end
|
||||||
|
|
||||||
|
def assert_error_about_closed_deliverable(time_entry)
|
||||||
|
assert_equal "Can't create a time entry on a closed deliverable", time_entry.errors.on_base
|
||||||
|
end
|
||||||
|
|
||||||
|
def assert_error_about_closed_contract(time_entry)
|
||||||
|
assert_equal "Can't create a time entry on a closed contract", time_entry.errors.on_base
|
||||||
|
end
|
||||||
|
|
||||||
|
should "allow logging time to an issue on an open deliverable, open contract" do
|
||||||
|
assert_difference("TimeEntry.count") { create_time_entry }
|
||||||
|
end
|
||||||
|
|
||||||
|
should "block logging time to an issue on a locked deliverable, open contract" do
|
||||||
|
assert @deliverable.lock!
|
||||||
|
assert @deliverable.locked?
|
||||||
|
|
||||||
|
assert_no_difference("TimeEntry.count") { create_time_entry }
|
||||||
|
assert_error_about_locked_deliverable(@time_entry)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "block logging time to an issue on an open deliverable, locked contract" do
|
||||||
|
assert @contract.lock!
|
||||||
|
assert @contract.locked?
|
||||||
|
|
||||||
|
assert_no_difference("TimeEntry.count") { create_time_entry }
|
||||||
|
assert_error_about_locked_contract(@time_entry)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "block logging time to an issue on a locked deliverable, locked contract" do
|
||||||
|
assert @deliverable.lock!
|
||||||
|
assert @deliverable.locked?
|
||||||
|
assert @contract.lock!
|
||||||
|
assert @contract.locked?
|
||||||
|
|
||||||
|
assert_no_difference("TimeEntry.count") { create_time_entry }
|
||||||
|
assert @time_entry.errors.on_base.include?("Can't create a time entry on a locked deliverable")
|
||||||
|
assert @time_entry.errors.on_base.include?("Can't create a time entry on a locked contract")
|
||||||
|
end
|
||||||
|
|
||||||
|
should "block logging time to an issue on a closed deliverable, open contract" do
|
||||||
|
assert @deliverable.close!
|
||||||
|
assert @deliverable.closed?
|
||||||
|
|
||||||
|
assert_no_difference("TimeEntry.count") { create_time_entry }
|
||||||
|
assert_error_about_closed_deliverable(@time_entry)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "block logging time to an issue on a closed deliverable, locked contract" do
|
||||||
|
assert @deliverable.close!
|
||||||
|
assert @deliverable.closed?
|
||||||
|
assert @contract.lock!
|
||||||
|
assert @contract.locked?
|
||||||
|
|
||||||
|
assert_no_difference("TimeEntry.count") { create_time_entry }
|
||||||
|
assert @time_entry.errors.on_base.include?("Can't create a time entry on a closed deliverable")
|
||||||
|
assert @time_entry.errors.on_base.include?("Can't create a time entry on a locked contract")
|
||||||
|
end
|
||||||
|
|
||||||
|
should "block logging time to an issue on an open deliverable, closed contract" do
|
||||||
|
assert @contract.close!
|
||||||
|
assert @contract.closed?
|
||||||
|
|
||||||
|
assert_no_difference("TimeEntry.count") { create_time_entry }
|
||||||
|
assert_error_about_closed_contract(@time_entry)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "block logging time to an issue on a locked deliverable, closed contract" do
|
||||||
|
assert @deliverable.lock!
|
||||||
|
assert @deliverable.locked?
|
||||||
|
assert @contract.close!
|
||||||
|
assert @contract.closed?
|
||||||
|
|
||||||
|
assert_no_difference("TimeEntry.count") { create_time_entry }
|
||||||
|
assert @time_entry.errors.on_base.include?("Can't create a time entry on a locked deliverable")
|
||||||
|
assert @time_entry.errors.on_base.include?("Can't create a time entry on a closed contract")
|
||||||
|
end
|
||||||
|
|
||||||
|
should "block logging time to an issue on a closed deliverable, closed contract" do
|
||||||
|
assert @deliverable.close!
|
||||||
|
assert @deliverable.closed?
|
||||||
|
assert @contract.close!
|
||||||
|
assert @contract.closed?
|
||||||
|
|
||||||
|
assert_no_difference("TimeEntry.count") { create_time_entry }
|
||||||
|
assert @time_entry.errors.on_base.include?("Can't create a time entry on a closed deliverable")
|
||||||
|
assert @time_entry.errors.on_base.include?("Can't create a time entry on a closed contract")
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
Reference in new issue
Block a user