Skip to content

Commit

Permalink
CRM457-2216 part 4: Allow storage of pending (mid-adjustments) states…
Browse files Browse the repository at this point in the history
… and non-timestamp-affecting events (#324)

## Description of change
The app store needs to be able to hold onto the state of a submission as
each adjustment is made by the caseworker without bumping the submission
version each time. It achieves this by putting everything in a "pending"
version that can be built up over time and eventually replaced by the
full new version.

[Link to relevant
ticket](https://dsdmoj.atlassian.net/browse/CRM457-2216)
  • Loading branch information
patrick-laa authored Nov 11, 2024
1 parent 3d56b4c commit 3df8687
Show file tree
Hide file tree
Showing 11 changed files with 151 additions and 4 deletions.
20 changes: 20 additions & 0 deletions app/controllers/V1/adjustments_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module V1
class AdjustmentsController < ApplicationController
def create
::Submissions::AdjustmentService.call(current_submission, params)
head :created
rescue ActiveRecord::RecordInvalid => e
render json: { errors: e.message }, status: :unprocessable_entity
end

private

def current_submission
@current_submission ||= Submission.find(params[:submission_id])
end

def authorization_object
current_submission
end
end
end
8 changes: 7 additions & 1 deletion app/services/authorization/rules.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ module Rules
auto_assignments: true,
},
events: {
create: ->(object, _params) { object.state.in?(%w[submitted sent_back provider_updated]) },
create: ->(object, _params) { object.state.in?(EDITABLE_BY_CASEWORKER_STATES) },
},
assignments: {
create: true,
Expand All @@ -35,9 +35,15 @@ module Rules
searches: {
create: true,
},
adjustments: {
create: ->(object, _params) { object.state.in?(EDITABLE_BY_CASEWORKER_STATES) },
},
},
}.freeze

# Pre-RFI NSM claims are editable in the sent-back state.
EDITABLE_BY_CASEWORKER_STATES = %w[submitted sent_back provider_updated].freeze

PERMITTED_SUBMISSION_STATE_CHANGES = {
provider: [
{ pre: %w[sent_back], post: %w[provider_updated] },
Expand Down
16 changes: 16 additions & 0 deletions app/services/submissions/adjustment_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module Submissions
class AdjustmentService
class << self
def call(submission, params)
submission.with_lock do
pending_version = submission.ordered_submission_versions.find_or_initialize_by(pending: true) do |new_pending_version|
new_pending_version.version = submission.current_version + 1
new_pending_version.json_schema_version = submission.latest_version.json_schema_version
end

pending_version.update!(application: params[:application])
end
end
end
end
end
2 changes: 1 addition & 1 deletion app/services/submissions/event_addition_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def call(submission, params)
submission.events << event.as_json
end

latest_event = submission.events.max_by { |ev| ev["created_at"] }
latest_event = submission.events.reject { _1["does_not_constitute_update"] }.max_by { _1["created_at"] }
submission.last_updated_at = latest_event["created_at"] if latest_event
end
end
Expand Down
1 change: 1 addition & 0 deletions app/services/submissions/update_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ def call(submission, params, role)
submission.current_version += 1
EventAdditionService.call(submission, params)
submission.update!(params.permit(:application_risk).merge(state: params[:application_state]))
submission.ordered_submission_versions.where(pending: true).destroy_all
add_new_version(submission, params)
end
NotificationService.call(submission, role)
Expand Down
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
namespace "v1" do
resources :submissions, only: %i[show create index update] do
resources :events, only: %i[create]
resources :adjustments, only: %i[create]
resource :assignment, only: %i[create destroy]
member { patch :metadata }
collection { post :auto_assignments }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddPendingToApplicationVersion < ActiveRecord::Migration[7.2]
def change
add_column :application_version, :pending, :boolean, default: false
end
end
3 changes: 2 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[7.2].define(version: 2024_11_05_163348) do
ActiveRecord::Schema[7.2].define(version: 2024_11_11_091017) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"

Expand Down Expand Up @@ -39,6 +39,7 @@
t.datetime "created_at", precision: nil
t.datetime "updated_at", precision: nil
t.virtual "search_fields", type: :tsvector, as: "((((((setweight(to_tsvector('simple'::regconfig, replace(COALESCE(((application -> 'defendant'::text) ->> 'first_name'::text), ''::text), '/'::text, '-'::text)), 'B'::\"char\") || setweight(to_tsvector('simple'::regconfig, replace(COALESCE(((application -> 'defendant'::text) ->> 'last_name'::text), ''::text), '/'::text, '-'::text)), 'B'::\"char\")) || setweight(to_tsvector('simple'::regconfig, (replace((jsonb_path_query_array(application, '$.\"defendants\"[*].\"first_name\"'::jsonpath))::text, '/'::text, '-'::text))::jsonb), 'B'::\"char\")) || setweight(to_tsvector('simple'::regconfig, (replace((jsonb_path_query_array(application, '$.\"defendants\"[*].\"last_name\"'::jsonpath))::text, '/'::text, '-'::text))::jsonb), 'B'::\"char\")) || setweight(to_tsvector('simple'::regconfig, replace(COALESCE(((application -> 'firm_office'::text) ->> 'name'::text), ''::text), '/'::text, '-'::text)), 'B'::\"char\")) || setweight(to_tsvector('simple'::regconfig, COALESCE((application ->> 'ufn'::text), ''::text)), 'A'::\"char\")) || setweight(to_tsvector('simple'::regconfig, replace(lower(COALESCE((application ->> 'laa_reference'::text), ''::text)), '-'::text, ''::text)), 'A'::\"char\"))", stored: true
t.boolean "pending", default: false
t.index ["search_fields"], name: "index_application_version_on_search_fields", using: :gin
end

Expand Down
38 changes: 38 additions & 0 deletions spec/requests/adjust_submission_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
require "rails_helper"

RSpec.describe "Adjust submission" do
before { allow(Tokens::VerificationService).to receive(:call).and_return(valid: true, role: :caseworker) }

let(:submission) { create(:submission) }

it "validates" do
post "/v1/submissions/#{submission.id}/adjustments", params: {}
expect(response).to have_http_status(:unprocessable_entity)
end

context "when there is no pending version" do
it "adds a new pending version" do
post "/v1/submissions/#{submission.id}/adjustments", params: { application: { new: :data } }
expect(response).to have_http_status(:created)
expect(submission.reload.current_version).to eq 1
expect(submission.latest_version).to have_attributes(
application: { "new" => "data" },
version: 2,
)
end
end

context "when there is a pending version" do
let(:pending_version) { create(:submission_version, submission:, application: { "old" => "data" }, pending: true) }

before { pending_version }

it "replaces the pending version data" do
post "/v1/submissions/#{submission.id}/adjustments", params: { application: { new: :data } }
expect(response).to have_http_status(:created)
expect(pending_version.reload).to have_attributes(
application: { "new" => "data" },
)
end
end
end
54 changes: 53 additions & 1 deletion spec/requests/create_events_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

RSpec.describe "Create events" do
context "when authenticated with bearer token" do
let(:submission) { create(:submission, state:) }
let(:submission) { create(:submission, state:, last_updated_at: old_timestamp) }
let(:state) { "submitted" }
let(:old_timestamp) { 3.days.ago }

before { allow(Tokens::VerificationService).to receive(:call).and_return(valid: true, role: :caseworker) }

Expand Down Expand Up @@ -74,5 +75,56 @@
expect(response).to have_http_status :created
expect(submission.reload.state).to eq("submitted")
end

it "bumps last updated at to implicit timestamp" do
freeze_time

post "/v1/submissions/#{submission.id}/events", params: {
events: [
{
id: "A",
details: "history",
},
],
}
expect(response).to have_http_status :created

expect(submission.reload.last_updated_at).to eq Time.current
end

it "bumps last updated at to explicit timestamp" do
freeze_time

post "/v1/submissions/#{submission.id}/events", params: {
events: [
{
id: "A",
details: "history",
created_at: 2.hours.ago,
},
],
}
expect(response).to have_http_status :created

expect(submission.reload.last_updated_at).to eq 2.hours.ago
end

it "ignores timestamps if commandeed" do
freeze_time

post "/v1/submissions/#{submission.id}/events", params: {
events: [
{
id: "A",
details: "history",
created_at: 2.hours.ago,
does_not_constitute_update: true,
},
],
}
expect(response).to have_http_status :created

expect(submission.reload.last_updated_at).to eq 3.days.ago
end
end
end
7 changes: 7 additions & 0 deletions spec/requests/update_submission_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,11 @@
}
expect { patch("/v1/submissions/#{submission.id}", params:) }.to have_enqueued_job
end

it "clears out pending versions" do
submission = create(:submission)
pending_version = create :submission_version, submission:, pending: true
patch "/v1/submissions/#{submission.id}", params: { application_state: "granted", application: { new: :data }, json_schema_version: 1 }
expect(submission.ordered_submission_versions.find_by(id: pending_version.id)).to be_nil
end
end

0 comments on commit 3df8687

Please sign in to comment.