diff --git a/app/models/contract.rb b/app/models/contract.rb
index e734b7a..6ebf8a1 100644
--- a/app/models/contract.rb
+++ b/app/models/contract.rb
@@ -19,6 +19,7 @@ class Contract < ActiveRecord::Base
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_on_update :validate_status_changes
# Accessors
attr_accessible :name
@@ -56,6 +57,10 @@ class Contract < ActiveRecord::Base
update_attribute(:status, "closed")
end
+ def open?
+ self.status == "open"
+ end
+
def locked?
self.status == "locked"
end
@@ -261,6 +266,30 @@ class Contract < ActiveRecord::Base
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
# that are not assigned to a Deliverable
def orphaned_time
@@ -279,6 +308,12 @@ class Contract < ActiveRecord::Base
generator_for :executed => true
generator_for(:start_date) { Date.yesterday }
generator_for(:end_date) { Date.tomorrow }
+ generator_for :discount, ''
+ generator_for :details, ''
+ generator_for :discount_note, ''
+ generator_for :client_point_of_contact, ''
+ generator_for :client_ap_contact_information, ''
+ generator_for :po_number, ''
def self.next_name
@last_name ||= 'Contract 0000'
diff --git a/app/models/deliverable.rb b/app/models/deliverable.rb
index dd96315..e6a24ac 100644
--- a/app/models/deliverable.rb
+++ b/app/models/deliverable.rb
@@ -96,6 +96,7 @@ class Deliverable < ActiveRecord::Base
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?
diff --git a/app/views/contracts/_form.html.erb b/app/views/contracts/_form.html.erb
index 8a762cc..103874a 100644
--- a/app/views/contracts/_form.html.erb
+++ b/app/views/contracts/_form.html.erb
@@ -1,3 +1,9 @@
+<% if resource.locked? || resource.closed? %>
+
+
<%= resource.locked? ? l(:text_contract_locked_warning) : l(:text_contract_closed_warning) %>
+
+<% end %>
+
<% form.inputs :name => l(:text_general_legend) do %>
<%= form.input :name, :required => true %>
diff --git a/config/locales/en.yml b/config/locales/en.yml
index ddaeb5e..5c5f407 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -7,6 +7,8 @@ en:
cant_assign_to_locked_deliverable: "Can't assign issue to a locked deliverable"
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"
field_end_date: End Date
field_executed: Executed
@@ -92,3 +94,5 @@ en:
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."
diff --git a/test/integration/contracts_edit_test.rb b/test/integration/contracts_edit_test.rb
index 5115067..d302cf4 100644
--- a/test/integration/contracts_edit_test.rb
+++ b/test/integration/contracts_edit_test.rb
@@ -48,13 +48,139 @@ class ContractsEditTest < ActionController::IntegrationTest
end
fill_in "Name", :with => 'An updated name'
- select "Locked", :from => "Status"
click_button "Save Contract"
assert_response :success
assert_template 'contracts/show'
assert_equal "An updated name", @contract.reload.name
- assert_equal "locked", @contract.reload.status
+ 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