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