Skip to content
7 changes: 7 additions & 0 deletions app/controllers/audits_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
class AuditsController < ApplicationController
before_action :authorize_admin
before_action :set_audit, only: %i(show edit update destroy finalize)
before_action :ensure_audit_is_editable, only: %i(finalize update)

def index
@selected_location = filter_params[:at_location]
Expand Down Expand Up @@ -80,6 +81,12 @@ def destroy

private

def ensure_audit_is_editable
if @audit.reload.finalized?
redirect_to audit_path(@audit), error: "This audit has been finalized and cannot be edited."
end
end

def handle_audit_errors
error_message = @audit.errors.uniq(&:attribute).map do |error|
attr = (error.attribute.to_s == 'base') ? '' : error.attribute.capitalize
Expand Down
14 changes: 14 additions & 0 deletions app/models/account_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class AccountRequest < ApplicationRecord

validate :email_not_already_used_by_organization
validate :email_not_already_used_by_user
validate :cannot_change_status_once_rejected,
:cannot_change_status_once_closed, on: :update

belongs_to :ndbn_member, class_name: 'NDBNMember', optional: true

Expand Down Expand Up @@ -100,4 +102,16 @@ def email_not_already_used_by_user
errors.add(:email, 'already used by an existing User')
end
end

def cannot_change_status_once_rejected
if status_changed? && status_was == "rejected"
errors.add(:status, "cannot be changed once rejected")
end
end

def cannot_change_status_once_closed
if status_changed? && status_was == "admin_closed"
errors.add(:status, "cannot be changed once closed by an admin")
end
end
end
7 changes: 7 additions & 0 deletions app/models/audit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class Audit < ApplicationRecord
validate :line_items_quantity_is_not_negative
validate :line_items_unique_by_item_id
validate :user_is_organization_admin_of_the_organization
validate :cannot_change_status_once_finalized, on: :update

def self.finalized_since?(itemizable, *location_ids)
item_ids = itemizable.line_items.pluck(:item_id)
Expand Down Expand Up @@ -86,4 +87,10 @@ def line_items_unique_by_item_id
def line_items_quantity_is_not_negative
line_items_quantity_is_at_least(0)
end

def cannot_change_status_once_finalized
if status_changed? && status_was == "finalized"
errors.add(:status, "cannot be changed once finalized")
end
end
end
24 changes: 24 additions & 0 deletions spec/models/account_request_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,30 @@
end
end

describe '#status' do
it "does not regress from rejected to another status" do
rejected_request = create(:account_request, status: 'rejected')

expect { rejected_request.confirm! }
.to raise_error(ActiveRecord::RecordInvalid, /cannot be changed once rejected/)
end

it "does not regress from admin_closed to another status" do
rejected_request = create(:account_request, status: 'admin_closed')

expect { rejected_request.confirm! }
.to raise_error(ActiveRecord::RecordInvalid, /cannot be changed once closed by an admin/)
end

it "allows normal transitions" do
started_request = create(:account_request, status: 'started')
user_confirmed_request = create(:account_request, status: 'user_confirmed')

expect { started_request.confirm! }.not_to raise_error
expect { user_confirmed_request.reject!('rejectable request') }.not_to raise_error
end
end

describe '.get_by_identity_token' do
subject { described_class.get_by_identity_token(identity_token) }

Expand Down
17 changes: 17 additions & 0 deletions spec/models/audit_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,23 @@

expect(audit.save).to be_truthy
end

describe '#status' do
it "does not regress from finalized to another status" do
finalized_audit = create(:audit, organization:, status: :finalized)

expect { finalized_audit.update!(status: :confirmed) }
.to raise_error(ActiveRecord::RecordInvalid, /cannot be changed once finalized/)
end

it "allows normal transitions" do
in_progress_audit = create(:audit, organization:, status: :in_progress)
confirmed_audit = create(:audit, organization:, status: :confirmed)

expect { in_progress_audit.update!(status: :confirmed) }.not_to raise_error
expect { confirmed_audit.update!(status: :finalized) }.not_to raise_error
end
end
end

context "Scopes >" do
Expand Down
54 changes: 50 additions & 4 deletions spec/requests/audits_requests_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,22 @@
{
organization_id: organization.id,
storage_location_id: storage_location.id,
user_id: create(:organization_admin, organization: organization).id
user_id: organization_admin.id
}
end

let(:invalid_storage_location_attributes) do
{
organization_id: organization.id,
storage_location_id: nil,
user_id: create(:organization_admin, organization: organization).id
user_id: organization_admin.id
}
end

let(:invalid_attributes) do
{ organization_id: nil }
end

let(:valid_session) { {} }

describe "while signed in as an organization admin" do
before do
sign_in(organization_admin)
Expand Down Expand Up @@ -109,6 +107,40 @@
end
end

describe "PUT #update" do
it "confirms the updated audit and redirects to the audit" do
audit = create(:audit, organization: organization, status: :in_progress)
item = create(:item)
audit.line_items << create(:line_item, quantity: 3, item: item)

put audit_path(id: audit.to_param, audit: {
storage_location_id: storage_location.id,
line_items_attributes: {"0" => {"item_id" => item.id, "quantity" => "4"}}
})

expect(response).to redirect_to(audit_path(audit))
expect(flash[:notice]).to include("Audit is confirmed.")
expect(audit.reload).to be_confirmed
end

context "when the audit has already been finalized" do
it "does not allow updates and redirects to the finalized audit" do
finalized_audit = create(:audit, organization: organization, status: :finalized)
item = create(:item)
finalized_audit.line_items << create(:line_item, quantity: 3, item: item)

put audit_path(id: finalized_audit.to_param, audit: {
storage_location_id: storage_location.id,
line_items_attributes: {"0" => {"item_id" => item.id, "quantity" => "4"}}
})

expect(response).to redirect_to(audit_path(finalized_audit))
expect(flash[:error]).to include("This audit has been finalized and cannot be edited.")
expect(finalized_audit.line_items.first.quantity).to eq(3)
end
end
end

describe "POST #create" do
context "with valid params" do
it "creates a new Audit" do
Expand All @@ -121,6 +153,7 @@
expect do
post audits_path(audit: valid_attributes, save_progress: '')
expect(Audit.last.in_progress?).to be_truthy
expect(flash[:notice]).to include("Audit's progress was successfully saved.")
end.to change(Audit.in_progress, :count).by(1)
end

Expand Down Expand Up @@ -170,6 +203,19 @@
expect(audit.reload).to be_finalized
expect(AuditEvent.count).to eq(1)
end

context "when the audit has already been finalized" do
it "does not create a new AuditEvent and redirects to the finalized audit" do
finalized_audit = create(:audit, organization: organization, status: :finalized)

expect do
post audit_finalize_path(audit_id: finalized_audit.to_param)
end.not_to change(AuditEvent, :count)

expect(response).to redirect_to(audit_path(finalized_audit))
expect(flash[:error]).to include("This audit has been finalized and cannot be edited.")
end
end
end

describe "DELETE #destroy" do
Expand Down
Loading