From f3301bd70bb2996e6d41c06a322caf9887adcf68 Mon Sep 17 00:00:00 2001 From: timpeat Date: Fri, 6 Sep 2024 14:44:10 +0100 Subject: [PATCH 1/3] Spike means testesd decision --- app/aggregates/deciding.rb | 22 +++++++ app/aggregates/deciding/command.rb | 31 ++++++++++ .../deciding/commands/create_draft.rb | 12 ++++ .../deciding/commands/load_decision.rb | 7 +++ .../commands/set_interests_of_justice.rb | 12 ++++ app/aggregates/deciding/decision.rb | 46 +++++++++++++++ app/aggregates/reviewing.rb | 2 + .../reviewing/available_reviewer_actions.rb | 3 +- app/aggregates/reviewing/command.rb | 2 +- .../reviewing/commands/add_decision.rb | 13 +++++ app/aggregates/reviewing/review.rb | 17 +++++- app/components/review_action_component.rb | 5 +- .../interests_of_justices_controller.rb | 50 ++++++++++++++++ .../casework/decisions/means_controller.rb | 57 +++++++++++++++++++ .../casework/decisions_controller.rb | 51 +++++++++++++++++ .../casework/funding_decisions_controller.rb | 51 +++++++++++++++++ app/lib/types.rb | 13 +++++ app/models/crime_application.rb | 4 ++ app/models/decision.rb | 3 + app/models/decisions/interests_of_justice.rb | 33 +++++++++++ app/models/decisions/outcome.rb | 10 ++++ app/models/interests_of_justice_decision.rb | 18 ++++++ app/views/casework/decisions/index.html.erb | 31 ++++++++++ .../interests_of_justices/edit.html.erb | 24 ++++++++ .../interests_of_justices/new.html.erb | 23 ++++++++ app/views/casework/decisions/show.html.erb | 25 ++++++++ .../casework/funding_decisions/new.html.erb | 18 ++++++ config/initializers/event_store.rb | 3 + config/locales/en/casework.yml | 8 +++ config/locales/en/helpers.yml | 16 +++++- config/routes.rb | 7 +++ config/settings.yml | 5 ++ spec/support/capybara_helpers.rb | 39 +++++++++++++ .../reviewing/a_non_means_application_spec.rb | 24 +++++++- ...wing_a_draft_maat_funding_decision_spec.rb | 0 35 files changed, 677 insertions(+), 8 deletions(-) create mode 100644 app/aggregates/deciding.rb create mode 100644 app/aggregates/deciding/command.rb create mode 100644 app/aggregates/deciding/commands/create_draft.rb create mode 100644 app/aggregates/deciding/commands/load_decision.rb create mode 100644 app/aggregates/deciding/commands/set_interests_of_justice.rb create mode 100644 app/aggregates/deciding/decision.rb create mode 100644 app/aggregates/reviewing/commands/add_decision.rb create mode 100644 app/controllers/casework/decisions/interests_of_justices_controller.rb create mode 100644 app/controllers/casework/decisions/means_controller.rb create mode 100644 app/controllers/casework/decisions_controller.rb create mode 100644 app/controllers/casework/funding_decisions_controller.rb create mode 100644 app/models/decision.rb create mode 100644 app/models/decisions/interests_of_justice.rb create mode 100644 app/models/decisions/outcome.rb create mode 100644 app/models/interests_of_justice_decision.rb create mode 100644 app/views/casework/decisions/index.html.erb create mode 100644 app/views/casework/decisions/interests_of_justices/edit.html.erb create mode 100644 app/views/casework/decisions/interests_of_justices/new.html.erb create mode 100644 app/views/casework/decisions/show.html.erb create mode 100644 app/views/casework/funding_decisions/new.html.erb create mode 100644 spec/support/capybara_helpers.rb create mode 100644 spec/system/casework/reviewing/viewing_a_draft_maat_funding_decision_spec.rb diff --git a/app/aggregates/deciding.rb b/app/aggregates/deciding.rb new file mode 100644 index 000000000..ae3916d8f --- /dev/null +++ b/app/aggregates/deciding.rb @@ -0,0 +1,22 @@ +module Deciding + class DraftCreated < RailsEventStore::Event; end + class InterestsOfJusticeSet < RailsEventStore::Event; end + + class << self + def stream_name(decision_id) + "Deciding$#{decision_id}" + end + end + + class Configuration + def call(event_store) + event_store.subscribe( + DecisionHandler, to: [Reviewing::AddDecision] + ) + end + end + + class DecisionHandler + def call(event); end + end +end diff --git a/app/aggregates/deciding/command.rb b/app/aggregates/deciding/command.rb new file mode 100644 index 000000000..198bfd8ce --- /dev/null +++ b/app/aggregates/deciding/command.rb @@ -0,0 +1,31 @@ +module Deciding + class Command < Dry::Struct + attribute :decision_id, Types::Uuid + + def with_decision(&block) + repository.with_aggregate( + Decision.new(decision_id), + stream_name, + &block + ) + end + + private + + def repository + @repository ||= AggregateRoot::Repository.new( + Rails.configuration.event_store + ) + end + + def stream_name + Deciding.stream_name(decision_id) + end + + class << self + def call(args) + new(args).call + end + end + end +end diff --git a/app/aggregates/deciding/commands/create_draft.rb b/app/aggregates/deciding/commands/create_draft.rb new file mode 100644 index 000000000..133400247 --- /dev/null +++ b/app/aggregates/deciding/commands/create_draft.rb @@ -0,0 +1,12 @@ +module Deciding + class CreateDraft < Command + attribute :application_id, Types::Uuid + attribute :user_id, Types::Uuid + + def call + with_decision do |decision| + decision.create_draft(user_id:) + end + end + end +end diff --git a/app/aggregates/deciding/commands/load_decision.rb b/app/aggregates/deciding/commands/load_decision.rb new file mode 100644 index 000000000..df336909e --- /dev/null +++ b/app/aggregates/deciding/commands/load_decision.rb @@ -0,0 +1,7 @@ +module Deciding + class LoadDecision < Command + def call + repository.load(Decision.new(decision_id), stream_name) + end + end +end diff --git a/app/aggregates/deciding/commands/set_interests_of_justice.rb b/app/aggregates/deciding/commands/set_interests_of_justice.rb new file mode 100644 index 000000000..4ed89b088 --- /dev/null +++ b/app/aggregates/deciding/commands/set_interests_of_justice.rb @@ -0,0 +1,12 @@ +module Deciding + class SetInterestsOfJustice < Command + attribute :user_id, Types::Uuid + attribute :details, Types::InterestsOfJusticeDecision + + def call + with_decision do |decision| + decision.set_interests_of_justice(user_id:, details:) + end + end + end +end diff --git a/app/aggregates/deciding/decision.rb b/app/aggregates/deciding/decision.rb new file mode 100644 index 000000000..071a98465 --- /dev/null +++ b/app/aggregates/deciding/decision.rb @@ -0,0 +1,46 @@ +module Deciding + class Decision + include AggregateRoot + + def initialize(decision_id) + @decision_id = decision_id + @application_id = nil + @case_id = nil + @maat_id = nil + @interests_of_justice = nil + @means = nil + @state = nil + end + + attr_reader :interests_of_justice, :decision_id + + def create_draft(user_id:, application_id:) + apply DraftCreated.new( + data: { decision_id:, application_id:, user_id: } + ) + end + + def set_interests_of_justice(user_id:, details:) + # TODO: ignore if not changed + apply InterestsOfJusticeSet.new( + data: { user_id:, details: } + ) + end + + on DraftCreated do |event| + @interests_of_justice = event.data.fetch(:details) + @application_id = event.data.fetch(:application_id) + @state = Types::DecisionState[:draft] + end + + on InterestsOfJusticeSet do |event| + @interests_of_justice = event.data.fetch(:details) + end + + def interests_of_justice + return if @interests_of_justice.nil? + + Types::InterestsOfJusticeDecision[@interests_of_justice] + end + end +end diff --git a/app/aggregates/reviewing.rb b/app/aggregates/reviewing.rb index e75eb17a4..a647a0ada 100644 --- a/app/aggregates/reviewing.rb +++ b/app/aggregates/reviewing.rb @@ -15,6 +15,8 @@ class CannotMarkAsReadyWhenSentBack < Error; end class CannotSendBackWhenCompleted < Error; end class NotReceived < Error; end + class DecisionAdded < Event; end + class << self def stream_name(application_id) "Reviewing$#{application_id}" diff --git a/app/aggregates/reviewing/available_reviewer_actions.rb b/app/aggregates/reviewing/available_reviewer_actions.rb index c08ca749b..e4cbd48e1 100644 --- a/app/aggregates/reviewing/available_reviewer_actions.rb +++ b/app/aggregates/reviewing/available_reviewer_actions.rb @@ -6,8 +6,7 @@ class AvailableReviewerActions marked_as_ready: [:complete, :send_back], }, non_means: { - open: [:complete, :send_back], - marked_as_ready: [:complete, :send_back] # TODO: remove once all non-means in this state processed + open: FeatureFlags.adding_decisions.enabled? ? [:add_funding_decision, :send_back] : [:complete, :send_back], }, pse: { open: [:complete] diff --git a/app/aggregates/reviewing/command.rb b/app/aggregates/reviewing/command.rb index 829e1583f..c00e6bbe4 100644 --- a/app/aggregates/reviewing/command.rb +++ b/app/aggregates/reviewing/command.rb @@ -17,7 +17,7 @@ def repository end def stream_name - Reviewing.stream_name(application_id) + "Reviewing$#{application_id}" end class << self diff --git a/app/aggregates/reviewing/commands/add_decision.rb b/app/aggregates/reviewing/commands/add_decision.rb new file mode 100644 index 000000000..83cb234dd --- /dev/null +++ b/app/aggregates/reviewing/commands/add_decision.rb @@ -0,0 +1,13 @@ +module Reviewing + class AddDecision < Command + attribute :application_id, Types::Uuid + attribute :user_id, Types::Uuid + attribute :decision_id, Types::Uuid + + def call + with_review do |review| + review.add_decision(user_id:, decision_id:) + end + end + end +end diff --git a/app/aggregates/reviewing/review.rb b/app/aggregates/reviewing/review.rb index e4f3fae03..2b81d641b 100644 --- a/app/aggregates/reviewing/review.rb +++ b/app/aggregates/reviewing/review.rb @@ -15,11 +15,12 @@ def initialize(id) @superseded_by = nil @parent_id = nil @work_stream = nil + @decision_ids = [] end attr_reader :id, :state, :return_reason, :reviewed_at, :reviewer_id, :submitted_at, :superseded_by, :superseded_at, :parent_id, - :work_stream, :application_type + :work_stream, :application_type, :decision_ids alias application_id id @@ -68,6 +69,16 @@ def mark_as_ready(user_id:) ) end + def add_decision(user_id:, decision_id:) + # raise unless Non-means application + # raise if completed / decision sent + # raise decision_ids.include?(decision_id) + + apply DecisionAdded.new( + data: { application_id:, user_id:, decision_id: } + ) + end + on ApplicationReceived do |event| @state = Types::ReviewState[:open] @received_at = event.timestamp @@ -77,6 +88,10 @@ def mark_as_ready(user_id:) @work_stream = event.data.fetch(:work_stream, Types::WorkStreamType['criminal_applications_team']) end + on DecisionAdded do |event| + @decision_ids << event.data.fetch(:decision_id) + end + on SentBack do |event| @state = Types::ReviewState[:sent_back] @return_reason = event.data.fetch(:reason, nil) diff --git a/app/components/review_action_component.rb b/app/components/review_action_component.rb index ed08301f1..0c28406c8 100644 --- a/app/components/review_action_component.rb +++ b/app/components/review_action_component.rb @@ -24,13 +24,16 @@ def target complete_crime_application_path(application) when :send_back new_crime_application_return_path(application) + when :add_funding_decision + crime_application_decisions_path(application) when :mark_as_ready ready_crime_application_path(application) end end def method - return :get if action == :send_back + return :get if %i[send_back].include? action + return :post if %i[add_funding_decision].include? action :put end diff --git a/app/controllers/casework/decisions/interests_of_justices_controller.rb b/app/controllers/casework/decisions/interests_of_justices_controller.rb new file mode 100644 index 000000000..1d26cb8de --- /dev/null +++ b/app/controllers/casework/decisions/interests_of_justices_controller.rb @@ -0,0 +1,50 @@ +module Casework + module Decisions + class InterestsOfJusticesController < Casework::BaseController + before_action :set_crime_application + + def edit + agg = Deciding::LoadDecision.call( + decision_id: params[:decision_id] + ) + + @interests_of_justice = ::Decisions::InterestsOfJustice.new(agg.interests_of_justice) + end + + def update + @interests_of_justice = ::Decisions::InterestsOfJustice.new( + interests_of_justice_params + ) + + @interests_of_justice.validate! + + Deciding::SetInterestsOfJustice.new( + decision_id: params[:decision_id], + user_id: current_user_id, + details: @interests_of_justice.attributes.deep_symbolize_keys + ).call + + redirect_to crime_application_decision_path( + crime_application_id: params[:crime_application_id], id: + params[:decision_id] + ) + rescue ActiveModel::ValidationError + render :edit + end + + private + + def draft_decision + @crime_application.decision + end + + def interests_of_justice_params + params[:decisions_interests_of_justice].permit( + :result, :reason, :assessed_by, :assessed_on + ) + end + + def set_means_decision; end + end + end +end diff --git a/app/controllers/casework/decisions/means_controller.rb b/app/controllers/casework/decisions/means_controller.rb new file mode 100644 index 000000000..9991a69ca --- /dev/null +++ b/app/controllers/casework/decisions/means_controller.rb @@ -0,0 +1,57 @@ +module Casework + module Decisions + class InterestsOfJusticesController < Casework::BaseController + before_action :set_crime_application + + def edit + @interests_of_justice = ::Decisions::InterestsOfJustice.new + end + + def update + @interests_of_justice = ::Decisions::InterestsOfJustice.new( + interests_of_justice_params + ) + + @interests_of_justice.validate! + + Deciding::SetInterestsOfJustice.new( + decision_id: params[:decision_id], + user_id: current_user_id, + details: @interests_of_justice.attributes.deep_symbolize_keys + ).call + + flash_and_redirect :success, :sent_back + rescue ActiveModel::ValidationError + render :edit + end + + private + + def draft_decision + @crime_application.decision + end + + def interests_of_justice_params + params[:decisions_interests_of_justice].permit( + :result, :reason, :assessed_by, :assessed_on + ) + end + + def create_draft_decision + Reviewing::CreateDraftDecision.new( + application_id: params[:crime_application_id], + user_id: current_user_id + ).call + end + + def set_ioj_decision + Reviewing::CreateDraftDecision.new( + application_id: params[:crime_application_id], + user_id: current_user_id + ).call + end + + def set_means_decision; end + end + end +end diff --git a/app/controllers/casework/decisions_controller.rb b/app/controllers/casework/decisions_controller.rb new file mode 100644 index 000000000..34c05b2b2 --- /dev/null +++ b/app/controllers/casework/decisions_controller.rb @@ -0,0 +1,51 @@ +module Casework + class DecisionsController < Casework::BaseController + before_action :set_crime_application + + def index + @decisions = current_crime_application.review.decision_ids.map do |decision_id| + Deciding::LoadDecision.call(decision_id:) + end + end + + def show + agg = Deciding::LoadDecision.call( + decision_id: params[:id] + ) + + @interests_of_justice = ::Decisions::InterestsOfJustice.new(**agg.interests_of_justice) + end + + def edit + redirect_to edit_crime_application_decision_interests_of_justice_path( + crime_application_id: params[:crime_application_id], decision_id: + params[:id] + ) + end + + def create + decision_id = SecureRandom.uuid + + ActiveRecord::Base.transaction do + Reviewing::AddDecision.new( + application_id: params[:crime_application_id], + user_id: current_user_id, + decision_id: decision_id + ).call + + Deciding::CreateDraft.new( + application_id: params[:crime_application_id], + user_id: current_user_id, + decision_id: decision_id + ).call + end + + # Should we change path to be case 1, case 2 etc + redirect_to edit_crime_application_decision_interests_of_justice_path( + crime_application_id: params[:crime_application_id], decision_id: decision_id + ) + end + + # TODO: scope decision by application + end +end diff --git a/app/controllers/casework/funding_decisions_controller.rb b/app/controllers/casework/funding_decisions_controller.rb new file mode 100644 index 000000000..6aa7eec21 --- /dev/null +++ b/app/controllers/casework/funding_decisions_controller.rb @@ -0,0 +1,51 @@ +module Casework + class FundingDecisionsController < Casework::BaseController + before_action :set_crime_application + + def new + render 'decisions/interests_of_justice/edit' + # @form_object = Decisions::InterestsOfJustice.new + end + + def create + throw params + end + + # rubocop:disable Metrics/MethodLength + def update + @return_details = Decisions::InterestsOfJustice.new(return_params) + + @return_details.validate! + + Reviewing::EditDecision.new( + application_id: params[:crime_application_id], + user_id: current_user_id, + decision_details: @return_details.attributes + ).call + + flash_and_redirect :success, :sent_back + rescue ActiveModel::ValidationError + render :new + rescue Reviewing::AlreadySentBack + flash_and_redirect :important, :already_sent_back + rescue Reviewing::CannotSendBackWhenCompleted + flash_and_redirect :important, :cannot_send_back_when_completed + end + # rubocop:enable Metrics/MethodLength + + private + + def flash_and_redirect(key, message) + flash[key] = I18n.t(message, scope: [:flash, key]) + if key == :success + redirect_to assigned_applications_path + else + redirect_to crime_application_path(params[:crime_application_id]) + end + end + + def step_params + params[:return_details].permit(:reason, :details) + end + end +end diff --git a/app/lib/types.rb b/app/lib/types.rb index 48efbcfb7..4c180cae1 100644 --- a/app/lib/types.rb +++ b/app/lib/types.rb @@ -34,6 +34,8 @@ module Types ReviewState = Symbol.default(:open).enum(*%i[open sent_back completed marked_as_ready]) + DecisionState = Symbol.enum(*%i[draft]) + ReviewType = Symbol.enum(*%i[means non_means pse]) CASEWORKER_ROLE = 'caseworker'.freeze @@ -57,6 +59,17 @@ module Types details: String ) + # MAAT also returns other result values which we may also need to handle. + MeansResult = String.enum('pass', 'fail') + InterestsOfJusticeResult = String.enum('pass', 'fail') + + InterestsOfJusticeDecision = Hash.schema( + result: InterestsOfJusticeResult, + reason: String, + assessed_by: String, + assessed_on: Date + ) + Report = String.enum(*%w[ caseworker_report processed_report diff --git a/app/models/crime_application.rb b/app/models/crime_application.rb index f55b1cf2e..a396312a5 100644 --- a/app/models/crime_application.rb +++ b/app/models/crime_application.rb @@ -43,6 +43,10 @@ def history @history ||= ApplicationHistory.new(application: self) end + def funding_decisions + @funding_decisions ||= [Mock::FundingDecision.draft_maat] + end + def to_param id end diff --git a/app/models/decision.rb b/app/models/decision.rb new file mode 100644 index 000000000..573cbb502 --- /dev/null +++ b/app/models/decision.rb @@ -0,0 +1,3 @@ +class Decision < ApplicationStruct + attribute :interests_of_justice, Types::InterestsOfJusticeDecision +end diff --git a/app/models/decisions/interests_of_justice.rb b/app/models/decisions/interests_of_justice.rb new file mode 100644 index 000000000..6ed6a05cf --- /dev/null +++ b/app/models/decisions/interests_of_justice.rb @@ -0,0 +1,33 @@ +# class Decisions::InterestsOfJustice < ApplicationStruct +# include ActiveModel::Type::Helpers::AcceptsMultiparameterTime.new +# +# attribute? :result, Types::Params::Nil | Types::InterestsOfJusticeResult +# attribute? :reason, Types::Params::Nil | Types::String +# attribute? :assessed_by, Types::Params::Nil | Types::String +# attribute? :assessed_on, Types::Params::Date +# +# validates :result, inclusion: { in: Types::InterestsOfJusticeResult.values } +# validates :reason, :assessed_by, presence: true +# validates :assessed_on, presence: true +# +# # def self.new(attributes) +# # super attributes.merge(assessed_on: +# # end +# + +module Decisions + class InterestsOfJustice + include ActiveModel::Model + include ActiveModel::Attributes + include ActiveRecord::AttributeAssignment + + attribute :result, :string + attribute :reason, :string + attribute :assessed_by, :string + attribute :assessed_on, :date + + validates :result, inclusion: { in: Types::InterestsOfJusticeResult.values } + validates :reason, :assessed_by, presence: true + validates :assessed_on, presence: true + end +end diff --git a/app/models/decisions/outcome.rb b/app/models/decisions/outcome.rb new file mode 100644 index 000000000..c9807bb3d --- /dev/null +++ b/app/models/decisions/outcome.rb @@ -0,0 +1,10 @@ +module Decisions + class Outcome < ApplicationStruct + OUTCOMES = [:failed_interests_of_justice, :granted].freeze + + attribute? :outcome, Types::Nil | Types::String + attribute? :reason, Types::Nil | Types::String + + validates :outcome, presence: true + end +end diff --git a/app/models/interests_of_justice_decision.rb b/app/models/interests_of_justice_decision.rb new file mode 100644 index 000000000..5bc6c1516 --- /dev/null +++ b/app/models/interests_of_justice_decision.rb @@ -0,0 +1,18 @@ +class InterestsOfJusticeDecision < ApplicationStruct + attribute :interests_of_justice, InterestsOfJusticeDecision +end + +class InterestsOfJusticeDecision + include ActiveModel::Model + include ActiveModel::Attributes + include ActiveRecord::AttributeAssignment + + attribute :result, :string + attribute :reason, :string + attribute :assessed_by, :string + attribute :assessed_on, :date + + validates :result, inclusion: { in: Types::InterestsOfJusticeResult.values } + validates :reason, :assessed_by, presence: true + validates :assessed_on, presence: true +end diff --git a/app/views/casework/decisions/index.html.erb b/app/views/casework/decisions/index.html.erb new file mode 100644 index 000000000..b373f4626 --- /dev/null +++ b/app/views/casework/decisions/index.html.erb @@ -0,0 +1,31 @@ +<% title ':K:LKJ:LKJ:LKJ' %> + + +<% @decisions.each do |decision| %> + <%= govuk_summary_card(title: 'Case') do |card| + + interests_of_justice = Decisions::InterestsOfJustice.new(decision.interests_of_justice) + + card.with_action { govuk_link_to('Change', { action: :edit, id: decision.decision_id }) } + card.with_summary_list do |list| + list.with_row do |row| + row.with_key { label_text(:result, scope: [:decisions, :interests_of_justice] ) } + row.with_value { interests_of_justice.result } + end + list.with_row do |row| + row.with_key { label_text(:reason, scope: [:decisions, :interests_of_justice] ) } + row.with_value { simple_format(interests_of_justice.reason) } + end + + list.with_row do |row| + row.with_key { label_text(:assessed_by, scope: [:decisions, :interests_of_justice] ) } + row.with_value { interests_of_justice.assessed_by } + end + list.with_row do |row| + row.with_key { label_text(:assessed_on, scope: [:decisions, :interests_of_justice] ) } + row.with_value { l interests_of_justice.assessed_on, format: :compact } + end + end + end %> +<% end %> + diff --git a/app/views/casework/decisions/interests_of_justices/edit.html.erb b/app/views/casework/decisions/interests_of_justices/edit.html.erb new file mode 100644 index 000000000..d452d12f2 --- /dev/null +++ b/app/views/casework/decisions/interests_of_justices/edit.html.erb @@ -0,0 +1,24 @@ +<% title 'TESING' %> + +
+
+

+ <%= @crime_application.reference %> +

+ + <%= form_with model: @interests_of_justice, + url: crime_application_decision_interests_of_justice_path(), method: :put do |f| %> + + <%= f.govuk_error_summary %> + + <%= f.govuk_collection_radio_buttons :result, + ::Types::InterestsOfJusticeResult.values, + :to_s + %> + <%= f.govuk_text_area :reason %> + <%= f.govuk_text_field :assessed_by %> + <%= f.govuk_date_field :assessed_on, maxlength_enabled: true %> + <%= f.govuk_submit %> + <% end %> +
+
diff --git a/app/views/casework/decisions/interests_of_justices/new.html.erb b/app/views/casework/decisions/interests_of_justices/new.html.erb new file mode 100644 index 000000000..f449f6464 --- /dev/null +++ b/app/views/casework/decisions/interests_of_justices/new.html.erb @@ -0,0 +1,23 @@ +<% title 'TESING' %> + +
+
+

+ <%= @crime_application.reference %> +

+ + <%= form_with model: @interests_of_justice, url: crime_application_add_ioj_decision_path(@crime_application), method: :post do |f| %> + + <%= f.govuk_error_summary %> + + <%= f.govuk_collection_radio_buttons :result, + ::Types::InterestsOfJusticeResult.values, + :to_s + %> + <%= f.govuk_text_area :reason %> + <%= f.govuk_text_field :assessed_by %> + <%= f.govuk_date_field :assessed_on, maxlength_enabled: true %> + <%= f.govuk_submit %> + <% end %> +
+
diff --git a/app/views/casework/decisions/show.html.erb b/app/views/casework/decisions/show.html.erb new file mode 100644 index 000000000..b18226aac --- /dev/null +++ b/app/views/casework/decisions/show.html.erb @@ -0,0 +1,25 @@ +<% title ':K:LKJ:LKJ:LKJ' %> + + +<%= govuk_summary_card(title: 'Case') do |card| + card.with_action { govuk_link_to('Change', { action: :edit }) } + card.with_summary_list do |list| + list.with_row do |row| + row.with_key { label_text(:result, scope: [:decisions, :interests_of_justice] ) } + row.with_value { @interests_of_justice.result } + end + list.with_row do |row| + row.with_key { label_text(:reason, scope: [:decisions, :interests_of_justice] ) } + row.with_value { simple_format(@interests_of_justice.reason) } + end + + list.with_row do |row| + row.with_key { label_text(:assessed_by, scope: [:decisions, :interests_of_justice] ) } + row.with_value { @interests_of_justice.assessed_by } + end + list.with_row do |row| + row.with_key { label_text(:assessed_on, scope: [:decisions, :interests_of_justice] ) } + row.with_value { l @interests_of_justice.assessed_on, format: :compact } + end + end +end %> diff --git a/app/views/casework/funding_decisions/new.html.erb b/app/views/casework/funding_decisions/new.html.erb new file mode 100644 index 000000000..6a606254f --- /dev/null +++ b/app/views/casework/funding_decisions/new.html.erb @@ -0,0 +1,18 @@ +<% title 'TESING' %> + +
+
+

+ <%= @crime_application.reference %> +

+ + <%= form_with model: @form_object, url: crime_application_funding_decisions_path(@crime_application.id) do |f| %> + <%= f.text_field :reason %> + + <%= f.govuk_error_summary %> + + <%= f.govuk_submit %> + <% end %> +
+
+ diff --git a/config/initializers/event_store.rb b/config/initializers/event_store.rb index 42f4ee4b6..4554db7a2 100644 --- a/config/initializers/event_store.rb +++ b/config/initializers/event_store.rb @@ -1,6 +1,8 @@ Rails.configuration.to_prepare do event_store = Rails.configuration.event_store = RailsEventStore::Client.new + Deciding::Configuration.new.call(event_store) + #Notifying NotifierConfiguration.new.call(event_store) @@ -9,4 +11,5 @@ ReceivedOnReports::Configuration.new.call(event_store) Reviews::Configuration.new.call(event_store) CaseworkerReports::Configuration.new.call(event_store) + end diff --git a/config/locales/en/casework.yml b/config/locales/en/casework.yml index 143661235..fe0cf1676 100644 --- a/config/locales/en/casework.yml +++ b/config/locales/en/casework.yml @@ -180,6 +180,13 @@ en: income_more_than: "%{prefix} more than £12,475?" income_details: Income income_details_partner: Partner's income + + decisions: + interests_of_justice: + result: Interests of justice test results + reason: Interests of justice reason + assessed_by: Interests of justice test caseworker name + assessed_on: Date of interests of justice test employments_title: Jobs employment_title: Job employments: @@ -575,6 +582,7 @@ en: calls_to_action: abandon_reassign_to_self: No, do not reassign + add_funding_decision: Add a funding decision assign_to_self: Assign to your list clear_search: Clear confirm_reassign_to_self: Yes, reassign diff --git a/config/locales/en/helpers.yml b/config/locales/en/helpers.yml index ee147de7f..205ca9306 100644 --- a/config/locales/en/helpers.yml +++ b/config/locales/en/helpers.yml @@ -2,10 +2,24 @@ en: helpers: back_link: Back + hint: + decisions_interests_of_justice: + assessed_on: For example, DD/MM/YYY + legend: + decisions_interests_of_justice: + result: What is the interests of justice test result? + assessed_on: Enter the date of assessment + label: + decisions_interests_of_justice: + result_options: + pass: Passed + fail: Refused + reason: What is the reason for this? + assessed_by: What is the name of the caseworker who assessed this? + submit: save_and_continue: Save and continue save_and_come_back_later: Save and come back later subjects: applicant: client applicant_and_partner: client %{conjunction} partner - diff --git a/config/routes.rb b/config/routes.rb index e41b20c05..b313269f7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -36,6 +36,13 @@ put :ready, on: :member resource :reassign, only: [:new, :create] resource :return, only: [:new, :create] + post 'add_a_funding_decision', to: 'decisions#create' + + resources :decisions do + scope module: :decisions do + resource :interests_of_justice + end + end end get 'applications/open/:work_stream', to: 'crime_applications#open', as: :open_work_stream diff --git a/config/settings.yml b/config/settings.yml index 1c4b83ee0..6504eed26 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -23,6 +23,11 @@ feature_flags: local: true staging: true production: true + adding_decisions: + local: true + staging: false + production: false + # For settings that vary by HostEnv name host_env_settings: phase_banner_tag: diff --git a/spec/support/capybara_helpers.rb b/spec/support/capybara_helpers.rb new file mode 100644 index 000000000..0eb2de564 --- /dev/null +++ b/spec/support/capybara_helpers.rb @@ -0,0 +1,39 @@ +module CapybaraHelpers + def fill_in_date(date) + fill_in('Day', with: date.mday) + fill_in('Month', with: date.month) + fill_in('Year', with: date.year) + end + + def fill_date(question, with: nil) + date = with || Time.zone.today + + within(find('legend', text: question).sibling('div.govuk-date-input')) do + fill_in_date(date) + end + end + + # radio buttons + def choose_answer(question, choice) + q = find('legend', text: question).sibling('div.govuk-radios') + + within q do + choose(choice) + end + end + + # check boxes + def choose_answers(question, choices = []) + q = find('legend', text: question).sibling('div.govuk-checkboxes') + + within q do + choices.each do |choice| + check(choice) + end + end + end + + def save_and_continue + click_button('Save and continue') + end +end diff --git a/spec/system/casework/reviewing/a_non_means_application_spec.rb b/spec/system/casework/reviewing/a_non_means_application_spec.rb index 5548e6cee..5abda5034 100644 --- a/spec/system/casework/reviewing/a_non_means_application_spec.rb +++ b/spec/system/casework/reviewing/a_non_means_application_spec.rb @@ -2,6 +2,8 @@ RSpec.describe 'Reviewing a Non-means application' do include_context 'with stubbed application' do + let(:feature_flag_enabled?) { false } + let(:application_data) do JSON.parse(LaaCrimeSchemas.fixture(1.0).read).merge( 'is_means_tested' => 'no', @@ -10,6 +12,10 @@ end before do + allow(FeatureFlags).to receive(:adding_decisions) { + instance_double(FeatureFlags::EnabledFeature, enabled?: feature_flag_enabled?) + } + allow(DatastoreApi::Requests::UpdateApplication).to receive(:new).and_return( instance_double(DatastoreApi::Requests::UpdateApplication, call: {}) ) @@ -20,10 +26,24 @@ it 'can be completed by the caseworker' do expect(page).to have_button('Send back to provider') - click_button 'Mark as completed' - expect(page).to have_content('You marked the application as complete') end + + context 'when adding decisions feature flag enabled' do + let(:feature_flag_enabled?) { true } + + before do + click_button 'Start' + choose_answer('What is the interests of justice test result?', 'Passed') + fill_in('What is the reason for this?', 'Test result reason details') + fill_in('Enter the name of the caseworker who assessed this', 'Zoe Blogs') + fill_date('Enter the date of assessment', Date.yesterday) + save_and_continue + end + + it 'can be completed by the caseworker' do + end + end end end diff --git a/spec/system/casework/reviewing/viewing_a_draft_maat_funding_decision_spec.rb b/spec/system/casework/reviewing/viewing_a_draft_maat_funding_decision_spec.rb new file mode 100644 index 000000000..e69de29bb From 1f3f834cbcd54fbe57358ebeff9c5a018b7a2137 Mon Sep 17 00:00:00 2001 From: timpeat Date: Mon, 16 Sep 2024 18:18:13 +0100 Subject: [PATCH 2/3] WIP extract from spike --- app/aggregates/deciding.rb | 4 + .../deciding/commands/create_draft.rb | 2 +- .../deciding/commands/set_funding_decision.rb | 13 ++++ .../commands/set_interests_of_justice.rb | 4 +- app/aggregates/deciding/decision.rb | 29 +++++-- app/components/decision_component.rb | 77 +++++++++++++++++++ app/components/funding_decision_component.rb | 29 +++++++ .../decisions/funding_decisions_controller.rb | 23 ++++++ .../interests_of_justices_controller.rb | 45 +++-------- .../casework/decisions_controller.rb | 11 ++- .../casework/funding_decisions_controller.rb | 51 ------------ app/controllers/concerns/editable_decision.rb | 42 ++++++++++ app/lib/types.rb | 4 +- app/models/decision.rb | 5 +- app/models/decisions/funding_decision_form.rb | 41 ++++++++++ app/models/decisions/interests_of_justice.rb | 35 ++------- .../decisions/interests_of_justice_form.rb | 46 +++++++++++ app/models/interests_of_justice_decision.rb | 2 +- .../decisions/funding_decisions/edit.html.erb | 22 ++++++ app/views/casework/decisions/index.html.erb | 33 +------- .../interests_of_justices/edit.html.erb | 6 +- app/views/casework/decisions/show.html.erb | 22 +----- config/application.rb | 2 + config/locales/en/casework.yml | 7 +- config/locales/en/helpers.yml | 19 ++++- config/routes.rb | 2 + 26 files changed, 382 insertions(+), 194 deletions(-) create mode 100644 app/aggregates/deciding/commands/set_funding_decision.rb create mode 100644 app/components/decision_component.rb create mode 100644 app/components/funding_decision_component.rb create mode 100644 app/controllers/casework/decisions/funding_decisions_controller.rb delete mode 100644 app/controllers/casework/funding_decisions_controller.rb create mode 100644 app/controllers/concerns/editable_decision.rb create mode 100644 app/models/decisions/funding_decision_form.rb create mode 100644 app/models/decisions/interests_of_justice_form.rb create mode 100644 app/views/casework/decisions/funding_decisions/edit.html.erb diff --git a/app/aggregates/deciding.rb b/app/aggregates/deciding.rb index ae3916d8f..144bb8102 100644 --- a/app/aggregates/deciding.rb +++ b/app/aggregates/deciding.rb @@ -1,6 +1,10 @@ module Deciding + class DecisionNotFound < StandardError; end + class ApplicationNotAssignedToUser < StandardError; end + class DraftCreated < RailsEventStore::Event; end class InterestsOfJusticeSet < RailsEventStore::Event; end + class FundingDecisionSet < RailsEventStore::Event; end class << self def stream_name(decision_id) diff --git a/app/aggregates/deciding/commands/create_draft.rb b/app/aggregates/deciding/commands/create_draft.rb index 133400247..fb1a1afd2 100644 --- a/app/aggregates/deciding/commands/create_draft.rb +++ b/app/aggregates/deciding/commands/create_draft.rb @@ -5,7 +5,7 @@ class CreateDraft < Command def call with_decision do |decision| - decision.create_draft(user_id:) + decision.create_draft(user_id:, application_id:) end end end diff --git a/app/aggregates/deciding/commands/set_funding_decision.rb b/app/aggregates/deciding/commands/set_funding_decision.rb new file mode 100644 index 000000000..190d8f5c3 --- /dev/null +++ b/app/aggregates/deciding/commands/set_funding_decision.rb @@ -0,0 +1,13 @@ +module Deciding + class SetFundingDecision < Command + attribute :user_id, Types::Uuid + attribute :result, Types::FundingDecisionResult + attribute :details, Types::String + + def call + with_decision do |decision| + decision.set_funding_decision(user_id:, result:, details:) + end + end + end +end diff --git a/app/aggregates/deciding/commands/set_interests_of_justice.rb b/app/aggregates/deciding/commands/set_interests_of_justice.rb index 4ed89b088..1709b71bb 100644 --- a/app/aggregates/deciding/commands/set_interests_of_justice.rb +++ b/app/aggregates/deciding/commands/set_interests_of_justice.rb @@ -1,11 +1,11 @@ module Deciding class SetInterestsOfJustice < Command attribute :user_id, Types::Uuid - attribute :details, Types::InterestsOfJusticeDecision + attribute :interests_of_justice, Types::InterestsOfJusticeDecision def call with_decision do |decision| - decision.set_interests_of_justice(user_id:, details:) + decision.set_interests_of_justice(user_id:, interests_of_justice:) end end end diff --git a/app/aggregates/deciding/decision.rb b/app/aggregates/deciding/decision.rb index 071a98465..5afb20f0d 100644 --- a/app/aggregates/deciding/decision.rb +++ b/app/aggregates/deciding/decision.rb @@ -8,11 +8,13 @@ def initialize(decision_id) @case_id = nil @maat_id = nil @interests_of_justice = nil + @result = nil + @details = nil @means = nil @state = nil end - attr_reader :interests_of_justice, :decision_id + attr_reader :interests_of_justice, :application_id, :decision_id, :result, :details def create_draft(user_id:, application_id:) apply DraftCreated.new( @@ -20,21 +22,32 @@ def create_draft(user_id:, application_id:) ) end - def set_interests_of_justice(user_id:, details:) + def set_interests_of_justice(user_id:, interests_of_justice:) # TODO: ignore if not changed apply InterestsOfJusticeSet.new( - data: { user_id:, details: } + data: { decision_id:, application_id:, user_id:, interests_of_justice: } ) end - + + def set_funding_decision(user_id:, result:, details:) + # TODO: ignore if not changed + apply FundingDecisionSet.new( + data: { decision_id:, application_id:, user_id:, result:, details: } + ) + end + on DraftCreated do |event| - @interests_of_justice = event.data.fetch(:details) @application_id = event.data.fetch(:application_id) @state = Types::DecisionState[:draft] end on InterestsOfJusticeSet do |event| - @interests_of_justice = event.data.fetch(:details) + @interests_of_justice = event.data.fetch(:interests_of_justice) + end + + on FundingDecisionSet do |event| + @result = event.data.fetch(:result) + @details = event.data.fetch(:details) end def interests_of_justice @@ -42,5 +55,9 @@ def interests_of_justice Types::InterestsOfJusticeDecision[@interests_of_justice] end + + def to_param + decision_id + end end end diff --git a/app/components/decision_component.rb b/app/components/decision_component.rb new file mode 100644 index 000000000..d85e5526d --- /dev/null +++ b/app/components/decision_component.rb @@ -0,0 +1,77 @@ +class DecisionComponent < ViewComponent::Base + + include ActionView::Helpers + include AppTextHelper + # include StepsHelper + + attr_reader :decision + + def initialize(decision:, decision_iteration:) + @decision = decision + @decision_iteration = decision_iteration + + super + end + + def call + govuk_summary_card(title:, actions:) do |card| + govuk_summary_list do |list| + if interests_of_justice.present? + list.with_row do |row| + row.with_key { label_text(:result, scope: [:decision, :interests_of_justice] ) } + row.with_value { interests_of_justice[:result] } + end + + list.with_row do |row| + row.with_key { label_text(:details, scope: [:decision, :interests_of_justice] ) } + row.with_value { simple_format(interests_of_justice[:details]) } + end + + list.with_row do |row| + row.with_key { label_text(:assessed_by, scope: [:decision, :interests_of_justice] ) } + row.with_value { interests_of_justice[:assessed_by] } + end + + list.with_row do |row| + row.with_key { label_text(:assessed_on, scope: [:decision, :interests_of_justice] ) } + row.with_value { l interests_of_justice[:assessed_on], format: :compact } + end + end + + list.with_row do |row| + row.with_key { label_text(:result, scope: [:decision] ) } + row.with_value { decision.result } + end + + list.with_row do |row| + row.with_key { label_text(:details, scope: [:decision] ) } + row.with_value { decision.details } + end + end + end + end + + private + + attr_reader :decision, :decision_iteration + + delegate :means, :interests_of_justice, to: :decision + + def actions + [ + govuk_link_to('Change', { action: :edit, id: decision.decision_id }), + govuk_link_to('Remove', { action: :edit, id: decision.decision_id }) + ] + end + + def title + safe_join(['Case', count].compact, ' ') + end + + def count + return unless decision_iteration + return unless decision_iteration.size > 1 + + decision_iteration.index + 1 + end +end diff --git a/app/components/funding_decision_component.rb b/app/components/funding_decision_component.rb new file mode 100644 index 000000000..9dcc2a6c5 --- /dev/null +++ b/app/components/funding_decision_component.rb @@ -0,0 +1,29 @@ +class FundingDecisionComponent < ViewComponent::Base + # Wraps the Govuk Summary Card component so that when used with + # .with_collection the item number is added to the card title. + + def initialize(decision:, decision_iteration:) + @item = item + @item_title = title + @item_iteration = item_iteration + + super + end + + def call + app_card_list + end + + def title + safe_join([@item_title, count].compact, ' ') + end + + private + + def count + return unless item_iteration + return unless item_iteration.size > 1 + + item_iteration.index + 1 + end +end diff --git a/app/controllers/casework/decisions/funding_decisions_controller.rb b/app/controllers/casework/decisions/funding_decisions_controller.rb new file mode 100644 index 000000000..c833964ce --- /dev/null +++ b/app/controllers/casework/decisions/funding_decisions_controller.rb @@ -0,0 +1,23 @@ +module Casework + module Decisions + class FundingDecisionsController < Casework::BaseController + include EditableDecision + + private + + def form_class + ::Decisions::FundingDecisionForm + end + + def permitted_params + params[:decisions_funding_decision_form].permit( + :result, :details + ) + end + + def next_step + crime_application_decisions_path + end + end + end +end diff --git a/app/controllers/casework/decisions/interests_of_justices_controller.rb b/app/controllers/casework/decisions/interests_of_justices_controller.rb index 1d26cb8de..693e8a4f1 100644 --- a/app/controllers/casework/decisions/interests_of_justices_controller.rb +++ b/app/controllers/casework/decisions/interests_of_justices_controller.rb @@ -1,50 +1,23 @@ module Casework module Decisions class InterestsOfJusticesController < Casework::BaseController - before_action :set_crime_application + include EditableDecision - def edit - agg = Deciding::LoadDecision.call( - decision_id: params[:decision_id] - ) - - @interests_of_justice = ::Decisions::InterestsOfJustice.new(agg.interests_of_justice) - end - - def update - @interests_of_justice = ::Decisions::InterestsOfJustice.new( - interests_of_justice_params - ) - - @interests_of_justice.validate! - - Deciding::SetInterestsOfJustice.new( - decision_id: params[:decision_id], - user_id: current_user_id, - details: @interests_of_justice.attributes.deep_symbolize_keys - ).call + private - redirect_to crime_application_decision_path( - crime_application_id: params[:crime_application_id], id: - params[:decision_id] - ) - rescue ActiveModel::ValidationError - render :edit + def form_class + ::Decisions::InterestsOfJusticeForm end - private - - def draft_decision - @crime_application.decision + def next_step + edit_crime_application_decision_funding_decision_path end - def interests_of_justice_params - params[:decisions_interests_of_justice].permit( - :result, :reason, :assessed_by, :assessed_on + def permitted_params + params[:decisions_interests_of_justice_form].permit( + :result, :details, :assessed_by, :assessed_on ) end - - def set_means_decision; end end end end diff --git a/app/controllers/casework/decisions_controller.rb b/app/controllers/casework/decisions_controller.rb index 34c05b2b2..0bd3823be 100644 --- a/app/controllers/casework/decisions_controller.rb +++ b/app/controllers/casework/decisions_controller.rb @@ -1,19 +1,18 @@ module Casework class DecisionsController < Casework::BaseController before_action :set_crime_application + before_action :set_decision, only: [:show] def index @decisions = current_crime_application.review.decision_ids.map do |decision_id| - Deciding::LoadDecision.call(decision_id:) + agg = Deciding::LoadDecision.call( + application_id: params[:crime_application_id], + decision_id: + ) end end def show - agg = Deciding::LoadDecision.call( - decision_id: params[:id] - ) - - @interests_of_justice = ::Decisions::InterestsOfJustice.new(**agg.interests_of_justice) end def edit diff --git a/app/controllers/casework/funding_decisions_controller.rb b/app/controllers/casework/funding_decisions_controller.rb deleted file mode 100644 index 6aa7eec21..000000000 --- a/app/controllers/casework/funding_decisions_controller.rb +++ /dev/null @@ -1,51 +0,0 @@ -module Casework - class FundingDecisionsController < Casework::BaseController - before_action :set_crime_application - - def new - render 'decisions/interests_of_justice/edit' - # @form_object = Decisions::InterestsOfJustice.new - end - - def create - throw params - end - - # rubocop:disable Metrics/MethodLength - def update - @return_details = Decisions::InterestsOfJustice.new(return_params) - - @return_details.validate! - - Reviewing::EditDecision.new( - application_id: params[:crime_application_id], - user_id: current_user_id, - decision_details: @return_details.attributes - ).call - - flash_and_redirect :success, :sent_back - rescue ActiveModel::ValidationError - render :new - rescue Reviewing::AlreadySentBack - flash_and_redirect :important, :already_sent_back - rescue Reviewing::CannotSendBackWhenCompleted - flash_and_redirect :important, :cannot_send_back_when_completed - end - # rubocop:enable Metrics/MethodLength - - private - - def flash_and_redirect(key, message) - flash[key] = I18n.t(message, scope: [:flash, key]) - if key == :success - redirect_to assigned_applications_path - else - redirect_to crime_application_path(params[:crime_application_id]) - end - end - - def step_params - params[:return_details].permit(:reason, :details) - end - end -end diff --git a/app/controllers/concerns/editable_decision.rb b/app/controllers/concerns/editable_decision.rb new file mode 100644 index 000000000..0322a82c5 --- /dev/null +++ b/app/controllers/concerns/editable_decision.rb @@ -0,0 +1,42 @@ +module EditableDecision + extend ActiveSupport::Concern + + included do + before_action :set_crime_application + before_action :set_decision + before_action :confirm_assigned + before_action :set_form + end + + def edit; end + + def update + @form_object.update_with_user!( + permitted_params, current_user_id + ) + + redirect_to next_step + rescue ActiveModel::ValidationError + render :edit + end + + private + + def set_decision + decision = Deciding::LoadDecision.call( + decision_id: params[:decision_id] + ) + + raise Deciding::DecisionNotFound unless decision.application_id == current_crime_application.id + + @decision = decision + end + + def set_form + @form_object = form_class.build(@decision) + end + + def confirm_assigned + raise Deciding::DecisionNotFound unless @crime_application.reviewable_by?(current_user_id) + end +end diff --git a/app/lib/types.rb b/app/lib/types.rb index 4c180cae1..60f5a8218 100644 --- a/app/lib/types.rb +++ b/app/lib/types.rb @@ -62,13 +62,15 @@ module Types # MAAT also returns other result values which we may also need to handle. MeansResult = String.enum('pass', 'fail') InterestsOfJusticeResult = String.enum('pass', 'fail') + FundingDecisionResult = String.enum(*%w[granted_on_ioj fail_on_ioj]) InterestsOfJusticeDecision = Hash.schema( result: InterestsOfJusticeResult, - reason: String, + details: String, assessed_by: String, assessed_on: Date ) + Report = String.enum(*%w[ caseworker_report diff --git a/app/models/decision.rb b/app/models/decision.rb index 573cbb502..2520d8317 100644 --- a/app/models/decision.rb +++ b/app/models/decision.rb @@ -1,3 +1,6 @@ class Decision < ApplicationStruct - attribute :interests_of_justice, Types::InterestsOfJusticeDecision + attribute? :interests_of_justice, Decisions::InterestsOfJustice + attribute? :result, Types::String + attribute? :details, Types::String + attribute? :decision_id, Types::Uuid end diff --git a/app/models/decisions/funding_decision_form.rb b/app/models/decisions/funding_decision_form.rb new file mode 100644 index 000000000..9422770d7 --- /dev/null +++ b/app/models/decisions/funding_decision_form.rb @@ -0,0 +1,41 @@ +module Decisions + class FundingDecisionForm + include ActiveModel::Model + include ActiveModel::Attributes + include ActiveRecord::AttributeAssignment + include ActiveModel::Dirty + + attribute :application_id, :immutable_string + attribute :decision_id, :immutable_string + + attribute :result, :string + attribute :details, :string + + validates :result, inclusion: { in: :possible_results } + + def possible_results + Types::FundingDecisionResult.values + end + + def update_with_user!(attributes, user_id) + assign_attributes(attributes) + validate! + return unless changed? + + Deciding::SetFundingDecision.new( + decision_id:, user_id:, result:, details: + ).call + end + + class << self + def build(decision) + new( + application_id: decision.application_id, + decision_id: decision.decision_id, + result: decision.result, + details: decision.details + ) + end + end + end +end diff --git a/app/models/decisions/interests_of_justice.rb b/app/models/decisions/interests_of_justice.rb index 6ed6a05cf..2aa237334 100644 --- a/app/models/decisions/interests_of_justice.rb +++ b/app/models/decisions/interests_of_justice.rb @@ -1,33 +1,8 @@ -# class Decisions::InterestsOfJustice < ApplicationStruct -# include ActiveModel::Type::Helpers::AcceptsMultiparameterTime.new -# -# attribute? :result, Types::Params::Nil | Types::InterestsOfJusticeResult -# attribute? :reason, Types::Params::Nil | Types::String -# attribute? :assessed_by, Types::Params::Nil | Types::String -# attribute? :assessed_on, Types::Params::Date -# -# validates :result, inclusion: { in: Types::InterestsOfJusticeResult.values } -# validates :reason, :assessed_by, presence: true -# validates :assessed_on, presence: true -# -# # def self.new(attributes) -# # super attributes.merge(assessed_on: -# # end -# - module Decisions - class InterestsOfJustice - include ActiveModel::Model - include ActiveModel::Attributes - include ActiveRecord::AttributeAssignment - - attribute :result, :string - attribute :reason, :string - attribute :assessed_by, :string - attribute :assessed_on, :date - - validates :result, inclusion: { in: Types::InterestsOfJusticeResult.values } - validates :reason, :assessed_by, presence: true - validates :assessed_on, presence: true + class InterestsOfJustice < ApplicationStruct + attribute :result, Types::InterestsOfJusticeResult + attribute :details, Types::String + attribute :assessed_by, Types::String + attribute :assessed_on, Types::Date end end diff --git a/app/models/decisions/interests_of_justice_form.rb b/app/models/decisions/interests_of_justice_form.rb new file mode 100644 index 000000000..6824514ca --- /dev/null +++ b/app/models/decisions/interests_of_justice_form.rb @@ -0,0 +1,46 @@ +module Decisions + class InterestsOfJusticeForm + include ActiveModel::Model + include ActiveModel::Attributes + include ActiveRecord::AttributeAssignment + include ActiveModel::Dirty + + attribute :application_id, :immutable_string + attribute :decision_id, :immutable_string + + attribute :result, :string + attribute :details, :string + attribute :assessed_by, :string + attribute :assessed_on, :date + + validates :result, inclusion: { in: :possible_results } + validates :details, :assessed_by, presence: true + validates :assessed_on, presence: true + + def possible_results + Types::InterestsOfJusticeResult.values + end + + def update_with_user!(attributes, user_id) + assign_attributes(attributes) + validate! + return unless changed? + + Deciding::SetInterestsOfJustice.new( + decision_id: decision_id, + user_id: user_id, + interests_of_justice: self.attributes.deep_symbolize_keys + ).call + end + + class << self + def build(decision) + new( + **(decision.interests_of_justice || {}), + application_id: decision.application_id, + decision_id: decision.decision_id + ) + end + end + end +end diff --git a/app/models/interests_of_justice_decision.rb b/app/models/interests_of_justice_decision.rb index 5bc6c1516..1cc300315 100644 --- a/app/models/interests_of_justice_decision.rb +++ b/app/models/interests_of_justice_decision.rb @@ -8,7 +8,7 @@ class InterestsOfJusticeDecision include ActiveRecord::AttributeAssignment attribute :result, :string - attribute :reason, :string + attribute :details, :string attribute :assessed_by, :string attribute :assessed_on, :date diff --git a/app/views/casework/decisions/funding_decisions/edit.html.erb b/app/views/casework/decisions/funding_decisions/edit.html.erb new file mode 100644 index 000000000..d63aaeab9 --- /dev/null +++ b/app/views/casework/decisions/funding_decisions/edit.html.erb @@ -0,0 +1,22 @@ +<% title 'TESING' %> + +
+
+

+ <%= @crime_application.reference %> +

+ + <%= form_with model: @form_object, + url: crime_application_decision_funding_decision_path(), method: :put do |f| %> + + <%= f.govuk_error_summary %> + + <%= f.govuk_collection_radio_buttons :result, + @form_object.possible_results, + :to_s + %> + <%= f.govuk_text_area :details %> + <%= f.govuk_submit %> + <% end %> +
+
diff --git a/app/views/casework/decisions/index.html.erb b/app/views/casework/decisions/index.html.erb index b373f4626..da29690d4 100644 --- a/app/views/casework/decisions/index.html.erb +++ b/app/views/casework/decisions/index.html.erb @@ -1,31 +1,6 @@ <% title ':K:LKJ:LKJ:LKJ' %> - - -<% @decisions.each do |decision| %> - <%= govuk_summary_card(title: 'Case') do |card| - - interests_of_justice = Decisions::InterestsOfJustice.new(decision.interests_of_justice) - - card.with_action { govuk_link_to('Change', { action: :edit, id: decision.decision_id }) } - card.with_summary_list do |list| - list.with_row do |row| - row.with_key { label_text(:result, scope: [:decisions, :interests_of_justice] ) } - row.with_value { interests_of_justice.result } - end - list.with_row do |row| - row.with_key { label_text(:reason, scope: [:decisions, :interests_of_justice] ) } - row.with_value { simple_format(interests_of_justice.reason) } - end - - list.with_row do |row| - row.with_key { label_text(:assessed_by, scope: [:decisions, :interests_of_justice] ) } - row.with_value { interests_of_justice.assessed_by } - end - list.with_row do |row| - row.with_key { label_text(:assessed_on, scope: [:decisions, :interests_of_justice] ) } - row.with_value { l interests_of_justice.assessed_on, format: :compact } - end - end - end %> -<% end %> +<%= render( + DecisionComponent.with_collection( + @decisions + )) %> diff --git a/app/views/casework/decisions/interests_of_justices/edit.html.erb b/app/views/casework/decisions/interests_of_justices/edit.html.erb index d452d12f2..05e6ad3f6 100644 --- a/app/views/casework/decisions/interests_of_justices/edit.html.erb +++ b/app/views/casework/decisions/interests_of_justices/edit.html.erb @@ -6,16 +6,16 @@ <%= @crime_application.reference %>

- <%= form_with model: @interests_of_justice, + <%= form_with model: @form_object, url: crime_application_decision_interests_of_justice_path(), method: :put do |f| %> <%= f.govuk_error_summary %> <%= f.govuk_collection_radio_buttons :result, - ::Types::InterestsOfJusticeResult.values, + @form_object.possible_results, :to_s %> - <%= f.govuk_text_area :reason %> + <%= f.govuk_text_area :details %> <%= f.govuk_text_field :assessed_by %> <%= f.govuk_date_field :assessed_on, maxlength_enabled: true %> <%= f.govuk_submit %> diff --git a/app/views/casework/decisions/show.html.erb b/app/views/casework/decisions/show.html.erb index b18226aac..a982539ca 100644 --- a/app/views/casework/decisions/show.html.erb +++ b/app/views/casework/decisions/show.html.erb @@ -1,25 +1,5 @@ <% title ':K:LKJ:LKJ:LKJ' %> -<%= govuk_summary_card(title: 'Case') do |card| - card.with_action { govuk_link_to('Change', { action: :edit }) } - card.with_summary_list do |list| - list.with_row do |row| - row.with_key { label_text(:result, scope: [:decisions, :interests_of_justice] ) } - row.with_value { @interests_of_justice.result } - end - list.with_row do |row| - row.with_key { label_text(:reason, scope: [:decisions, :interests_of_justice] ) } - row.with_value { simple_format(@interests_of_justice.reason) } - end +<%= render @decision %> - list.with_row do |row| - row.with_key { label_text(:assessed_by, scope: [:decisions, :interests_of_justice] ) } - row.with_value { @interests_of_justice.assessed_by } - end - list.with_row do |row| - row.with_key { label_text(:assessed_on, scope: [:decisions, :interests_of_justice] ) } - row.with_value { l @interests_of_justice.assessed_on, format: :compact } - end - end -end %> diff --git a/config/application.rb b/config/application.rb index 37dcaf4df..84017ab61 100644 --- a/config/application.rb +++ b/config/application.rb @@ -79,6 +79,8 @@ class Application < Rails::Application config.action_dispatch.rescue_responses.merge!( 'Reporting::ReportNotFound' => :not_found, 'Allocating::WorkStreamNotFound' => :not_found, + 'Deciding::DecisionNotFound' => :not_found, + 'Deciding::ApplicationNotAssignedToUser' => :forbidden, 'ApplicationController::ForbiddenError' => :forbidden ) end diff --git a/config/locales/en/casework.yml b/config/locales/en/casework.yml index fe0cf1676..9540786ca 100644 --- a/config/locales/en/casework.yml +++ b/config/locales/en/casework.yml @@ -181,12 +181,15 @@ en: income_details: Income income_details_partner: Partner's income - decisions: + decision: + card_title: Case interests_of_justice: result: Interests of justice test results - reason: Interests of justice reason + details: Interests of justice reason assessed_by: Interests of justice test caseworker name assessed_on: Date of interests of justice test + result: Overall result + details: Further information about the decision employments_title: Jobs employment_title: Job employments: diff --git a/config/locales/en/helpers.yml b/config/locales/en/helpers.yml index 205ca9306..a6417188b 100644 --- a/config/locales/en/helpers.yml +++ b/config/locales/en/helpers.yml @@ -2,21 +2,32 @@ en: helpers: back_link: Back + hint: - decisions_interests_of_justice: + decisions_interests_of_justice_form: assessed_on: For example, DD/MM/YYY + legend: - decisions_interests_of_justice: + decisions_interests_of_justice_form: result: What is the interests of justice test result? assessed_on: Enter the date of assessment + decisions_funding_decision_form: + result: What is the funding decision for this application? + label: - decisions_interests_of_justice: + decisions_interests_of_justice_form: result_options: pass: Passed fail: Refused - reason: What is the reason for this? + details: What is the reason for this? assessed_by: What is the name of the caseworker who assessed this? + decisions_funding_decision_form: + result_options: + granted_on_ioj: Granted + fail_on_ioj: Failed interests of justice test + details: Additional comments for the provider (optional) + submit: save_and_continue: Save and continue save_and_come_back_later: Save and come back later diff --git a/config/routes.rb b/config/routes.rb index b313269f7..9a7f47959 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,6 @@ Rails.application.routes.draw do mount DatastoreApi::HealthEngine::Engine => '/datastore' + mount RailsEventStore::Browser => "/res" if Rails.env.development? get :health, to: 'healthcheck#show' get :ping, to: 'healthcheck#ping' @@ -41,6 +42,7 @@ resources :decisions do scope module: :decisions do resource :interests_of_justice + resource :funding_decision end end end From 3eb2bc9d2d5e5f0d3867933abbf650fc6353da25 Mon Sep 17 00:00:00 2001 From: timpeat Date: Tue, 17 Sep 2024 16:31:46 +0100 Subject: [PATCH 3/3] wip --- app/aggregates/deciding/decision.rb | 15 ++---- app/aggregates/reviewing.rb | 1 + .../reviewing/commands/remove_decision.rb | 13 +++++ app/aggregates/reviewing/review.rb | 40 +++++++--------- app/components/decision_component.rb | 41 +++++++++------- app/components/decision_result_component.rb | 29 +++++++++++ app/components/review_action_component.rb | 16 +++++-- .../decisions/funding_decisions_controller.rb | 3 ++ .../interests_of_justices_controller.rb | 10 ++-- .../casework/decisions_controller.rb | 48 +++++++++++-------- app/controllers/concerns/editable_decision.rb | 7 ++- app/helpers/components_helper.rb | 4 ++ app/lib/types.rb | 1 - app/models/decisions/funding_decision_form.rb | 4 +- .../decisions/interests_of_justice_form.rb | 2 +- .../decisions/funding_decisions/edit.html.erb | 17 ++++--- app/views/casework/decisions/index.html.erb | 25 ++++++++-- .../interests_of_justices/edit.html.erb | 10 +++- app/views/casework/decisions/show.html.erb | 5 -- config/locales/en/casework.yml | 20 +++++++- config/routes.rb | 6 ++- 21 files changed, 207 insertions(+), 110 deletions(-) create mode 100644 app/aggregates/reviewing/commands/remove_decision.rb create mode 100644 app/components/decision_result_component.rb delete mode 100644 app/views/casework/decisions/show.html.erb diff --git a/app/aggregates/deciding/decision.rb b/app/aggregates/deciding/decision.rb index 5afb20f0d..537e082c6 100644 --- a/app/aggregates/deciding/decision.rb +++ b/app/aggregates/deciding/decision.rb @@ -4,17 +4,10 @@ class Decision def initialize(decision_id) @decision_id = decision_id - @application_id = nil - @case_id = nil - @maat_id = nil @interests_of_justice = nil - @result = nil - @details = nil - @means = nil - @state = nil end - attr_reader :interests_of_justice, :application_id, :decision_id, :result, :details + attr_accessor :application_id, :decision_id, :result, :details, :state def create_draft(user_id:, application_id:) apply DraftCreated.new( @@ -23,19 +16,17 @@ def create_draft(user_id:, application_id:) end def set_interests_of_justice(user_id:, interests_of_justice:) - # TODO: ignore if not changed apply InterestsOfJusticeSet.new( data: { decision_id:, application_id:, user_id:, interests_of_justice: } ) end - + def set_funding_decision(user_id:, result:, details:) - # TODO: ignore if not changed apply FundingDecisionSet.new( data: { decision_id:, application_id:, user_id:, result:, details: } ) end - + on DraftCreated do |event| @application_id = event.data.fetch(:application_id) @state = Types::DecisionState[:draft] diff --git a/app/aggregates/reviewing.rb b/app/aggregates/reviewing.rb index a647a0ada..8692bebea 100644 --- a/app/aggregates/reviewing.rb +++ b/app/aggregates/reviewing.rb @@ -16,6 +16,7 @@ class CannotSendBackWhenCompleted < Error; end class NotReceived < Error; end class DecisionAdded < Event; end + class DecisionRemoved < Event; end class << self def stream_name(application_id) diff --git a/app/aggregates/reviewing/commands/remove_decision.rb b/app/aggregates/reviewing/commands/remove_decision.rb new file mode 100644 index 000000000..3b3ef061d --- /dev/null +++ b/app/aggregates/reviewing/commands/remove_decision.rb @@ -0,0 +1,13 @@ +module Reviewing + class RemoveDecision < Command + attribute :application_id, Types::Uuid + attribute :user_id, Types::Uuid + attribute :decision_id, Types::Uuid + + def call + with_review do |review| + review.remove_decision(user_id:, decision_id:) + end + end + end +end diff --git a/app/aggregates/reviewing/review.rb b/app/aggregates/reviewing/review.rb index 2b81d641b..64184458f 100644 --- a/app/aggregates/reviewing/review.rb +++ b/app/aggregates/reviewing/review.rb @@ -4,23 +4,13 @@ class Review def initialize(id) @id = id - @application_type = nil - @state = nil - @return_reason = nil - @reviewer_id = nil - @reviewed_at = nil - @received_at = nil - @submitted_at = nil - @superseded_at = nil - @superseded_by = nil - @parent_id = nil - @work_stream = nil @decision_ids = [] end - attr_reader :id, :state, :return_reason, :reviewed_at, :reviewer_id, - :submitted_at, :superseded_by, :superseded_at, :parent_id, - :work_stream, :application_type, :decision_ids + attr_accessor :state, :return_reason, :reviewed_at, :reviewer_id, :submitted_at, :superseded_by, + :superseded_at, :parent_id, :work_stream, :application_type + + attr_reader :id, :decision_ids alias application_id id @@ -70,15 +60,17 @@ def mark_as_ready(user_id:) end def add_decision(user_id:, decision_id:) - # raise unless Non-means application - # raise if completed / decision sent - # raise decision_ids.include?(decision_id) - apply DecisionAdded.new( data: { application_id:, user_id:, decision_id: } ) end + def remove_decision(user_id:, decision_id:) + apply DecisionRemoved.new( + data: { application_id:, user_id:, decision_id: } + ) + end + on ApplicationReceived do |event| @state = Types::ReviewState[:open] @received_at = event.timestamp @@ -92,6 +84,10 @@ def add_decision(user_id:, decision_id:) @decision_ids << event.data.fetch(:decision_id) end + on DecisionRemoved do |event| + @decision_ids -= [event.data.fetch(:decision_id)] + end + on SentBack do |event| @state = Types::ReviewState[:sent_back] @return_reason = event.data.fetch(:reason, nil) @@ -123,15 +119,11 @@ def received? end def business_day - return nil unless @submitted_at - - BusinessDay.new(day_zero: @submitted_at) + BusinessDay.new(day_zero: @submitted_at) if @submitted_at.present? end def reviewed_on - return nil unless @reviewed_at - - @reviewed_at.in_time_zone('London').to_date + @reviewed_at.in_time_zone('London').to_date if @reviewed_at.present? end def available_reviewer_actions diff --git a/app/components/decision_component.rb b/app/components/decision_component.rb index d85e5526d..9363b116f 100644 --- a/app/components/decision_component.rb +++ b/app/components/decision_component.rb @@ -1,10 +1,6 @@ class DecisionComponent < ViewComponent::Base - include ActionView::Helpers include AppTextHelper - # include StepsHelper - - attr_reader :decision def initialize(decision:, decision_iteration:) @decision = decision @@ -14,37 +10,37 @@ def initialize(decision:, decision_iteration:) end def call - govuk_summary_card(title:, actions:) do |card| + govuk_summary_card(title:, actions:) do |_card| govuk_summary_list do |list| if interests_of_justice.present? list.with_row do |row| - row.with_key { label_text(:result, scope: [:decision, :interests_of_justice] ) } - row.with_value { interests_of_justice[:result] } + row.with_key { label_text(:result, scope: [:decision, :interests_of_justice]) } + row.with_value { ioj_result } end list.with_row do |row| - row.with_key { label_text(:details, scope: [:decision, :interests_of_justice] ) } + row.with_key { label_text(:details, scope: [:decision, :interests_of_justice]) } row.with_value { simple_format(interests_of_justice[:details]) } end list.with_row do |row| - row.with_key { label_text(:assessed_by, scope: [:decision, :interests_of_justice] ) } + row.with_key { label_text(:assessed_by, scope: [:decision, :interests_of_justice]) } row.with_value { interests_of_justice[:assessed_by] } end list.with_row do |row| - row.with_key { label_text(:assessed_on, scope: [:decision, :interests_of_justice] ) } + row.with_key { label_text(:assessed_on, scope: [:decision, :interests_of_justice]) } row.with_value { l interests_of_justice[:assessed_on], format: :compact } end end list.with_row do |row| - row.with_key { label_text(:result, scope: [:decision] ) } - row.with_value { decision.result } + row.with_key { label_text(:result, scope: [:decision]) } + row.with_value { render DecisionResultComponent.new(result: decision.result) } end - + list.with_row do |row| - row.with_key { label_text(:details, scope: [:decision] ) } + row.with_key { label_text(:details, scope: [:decision]) } row.with_value { decision.details } end end @@ -53,15 +49,24 @@ def call private + def ioj_result + t(interests_of_justice[:result], scope: [:values, :decision_result]) + end + attr_reader :decision, :decision_iteration delegate :means, :interests_of_justice, to: :decision def actions - [ - govuk_link_to('Change', { action: :edit, id: decision.decision_id }), - govuk_link_to('Remove', { action: :edit, id: decision.decision_id }) - ] + [change_link, remove_link].compact + end + + def remove_link + button_to('Remove', { action: :destroy, id: decision.decision_id }, method: :delete) + end + + def change_link + govuk_link_to('Change', { action: :edit, id: decision.decision_id }) end def title diff --git a/app/components/decision_result_component.rb b/app/components/decision_result_component.rb new file mode 100644 index 000000000..d3447e6ef --- /dev/null +++ b/app/components/decision_result_component.rb @@ -0,0 +1,29 @@ +class DecisionResultComponent < ViewComponent::Base + def initialize(result: nil) + @result = result + + super + end + + def call + return if result.nil? + + govuk_tag( + text: t(result, scope: [:values, :decision_result]), + colour: colour + ) + end + + private + + attr_reader :result + + def colour + case result + when /fail/ + 'red' + else + 'green' + end + end +end diff --git a/app/components/review_action_component.rb b/app/components/review_action_component.rb index 0c28406c8..48cddfa40 100644 --- a/app/components/review_action_component.rb +++ b/app/components/review_action_component.rb @@ -32,10 +32,20 @@ def target end def method - return :get if %i[send_back].include? action - return :post if %i[add_funding_decision].include? action + case action + when :send_back + :get + when :add_funding_decision + add_funding_decision_method + else + :put + end + end + + def add_funding_decision_method + return :get unless application.review.decision_ids.empty? - :put + :post end def warning diff --git a/app/controllers/casework/decisions/funding_decisions_controller.rb b/app/controllers/casework/decisions/funding_decisions_controller.rb index c833964ce..634ad9f49 100644 --- a/app/controllers/casework/decisions/funding_decisions_controller.rb +++ b/app/controllers/casework/decisions/funding_decisions_controller.rb @@ -1,8 +1,11 @@ module Casework module Decisions + # rename overall result? class FundingDecisionsController < Casework::BaseController include EditableDecision + before_action :set_form + private def form_class diff --git a/app/controllers/casework/decisions/interests_of_justices_controller.rb b/app/controllers/casework/decisions/interests_of_justices_controller.rb index 693e8a4f1..45992f3a4 100644 --- a/app/controllers/casework/decisions/interests_of_justices_controller.rb +++ b/app/controllers/casework/decisions/interests_of_justices_controller.rb @@ -3,21 +3,23 @@ module Decisions class InterestsOfJusticesController < Casework::BaseController include EditableDecision + before_action :set_form + private def form_class ::Decisions::InterestsOfJusticeForm end - def next_step - edit_crime_application_decision_funding_decision_path - end - def permitted_params params[:decisions_interests_of_justice_form].permit( :result, :details, :assessed_by, :assessed_on ) end + + def next_step + edit_crime_application_decision_funding_decision_path + end end end end diff --git a/app/controllers/casework/decisions_controller.rb b/app/controllers/casework/decisions_controller.rb index 0bd3823be..6ded05759 100644 --- a/app/controllers/casework/decisions_controller.rb +++ b/app/controllers/casework/decisions_controller.rb @@ -1,20 +1,18 @@ module Casework class DecisionsController < Casework::BaseController - before_action :set_crime_application - before_action :set_decision, only: [:show] + include EditableDecision + + before_action :set_decision, except: [:index, :create] def index @decisions = current_crime_application.review.decision_ids.map do |decision_id| - agg = Deciding::LoadDecision.call( + Deciding::LoadDecision.call( application_id: params[:crime_application_id], - decision_id: + decision_id: decision_id ) end end - def show - end - def edit redirect_to edit_crime_application_decision_interests_of_justice_path( crime_application_id: params[:crime_application_id], decision_id: @@ -22,29 +20,39 @@ def edit ) end + def confirm_destroy; end + def create decision_id = SecureRandom.uuid - ActiveRecord::Base.transaction do - Reviewing::AddDecision.new( - application_id: params[:crime_application_id], - user_id: current_user_id, - decision_id: decision_id - ).call + args = { + application_id: @crime_application.id, + user_id: current_user_id, + decision_id: decision_id + } - Deciding::CreateDraft.new( - application_id: params[:crime_application_id], - user_id: current_user_id, - decision_id: decision_id - ).call + ActiveRecord::Base.transaction do + Reviewing::AddDecision.call(**args) + Deciding::CreateDraft.call(**args) end - # Should we change path to be case 1, case 2 etc redirect_to edit_crime_application_decision_interests_of_justice_path( crime_application_id: params[:crime_application_id], decision_id: decision_id ) end - # TODO: scope decision by application + def destroy + args = { + application_id: @crime_application.id, + user_id: current_user_id, + decision_id: @decision.decision_id + } + + ActiveRecord::Base.transaction do + Reviewing::RemoveDecision.new(**args).call + end + + redirect_to action: :index + end end end diff --git a/app/controllers/concerns/editable_decision.rb b/app/controllers/concerns/editable_decision.rb index 0322a82c5..743ed598d 100644 --- a/app/controllers/concerns/editable_decision.rb +++ b/app/controllers/concerns/editable_decision.rb @@ -1,11 +1,10 @@ -module EditableDecision +module EditableDecision extend ActiveSupport::Concern included do before_action :set_crime_application before_action :set_decision before_action :confirm_assigned - before_action :set_form end def edit; end @@ -24,10 +23,10 @@ def update def set_decision decision = Deciding::LoadDecision.call( - decision_id: params[:decision_id] + decision_id: params[:decision_id] || params[:id] ) - raise Deciding::DecisionNotFound unless decision.application_id == current_crime_application.id + raise Deciding::DecisionNotFound unless decision.application_id == current_crime_application.id @decision = decision end diff --git a/app/helpers/components_helper.rb b/app/helpers/components_helper.rb index 712e8a332..ff84f1f48 100644 --- a/app/helpers/components_helper.rb +++ b/app/helpers/components_helper.rb @@ -11,6 +11,10 @@ def offence_dates(offence) render OffenceDatesComponent.new(offence:) end + def decision_result(result) + render DecisionResultComponent.new(result:) + end + def conflict_of_interest(codefendant) render ConflictOfInterestComponent.new(codefendant:) end diff --git a/app/lib/types.rb b/app/lib/types.rb index 60f5a8218..ee3005bb5 100644 --- a/app/lib/types.rb +++ b/app/lib/types.rb @@ -70,7 +70,6 @@ module Types assessed_by: String, assessed_on: Date ) - Report = String.enum(*%w[ caseworker_report diff --git a/app/models/decisions/funding_decision_form.rb b/app/models/decisions/funding_decision_form.rb index 9422770d7..bc5c7ef3d 100644 --- a/app/models/decisions/funding_decision_form.rb +++ b/app/models/decisions/funding_decision_form.rb @@ -11,14 +11,14 @@ class FundingDecisionForm attribute :result, :string attribute :details, :string - validates :result, inclusion: { in: :possible_results } + validates :result, inclusion: { in: :possible_results } def possible_results Types::FundingDecisionResult.values end def update_with_user!(attributes, user_id) - assign_attributes(attributes) + assign_attributes(attributes) validate! return unless changed? diff --git a/app/models/decisions/interests_of_justice_form.rb b/app/models/decisions/interests_of_justice_form.rb index 6824514ca..5bddd89ec 100644 --- a/app/models/decisions/interests_of_justice_form.rb +++ b/app/models/decisions/interests_of_justice_form.rb @@ -22,7 +22,7 @@ def possible_results end def update_with_user!(attributes, user_id) - assign_attributes(attributes) + assign_attributes(attributes) validate! return unless changed? diff --git a/app/views/casework/decisions/funding_decisions/edit.html.erb b/app/views/casework/decisions/funding_decisions/edit.html.erb index d63aaeab9..e2e0a67ae 100644 --- a/app/views/casework/decisions/funding_decisions/edit.html.erb +++ b/app/views/casework/decisions/funding_decisions/edit.html.erb @@ -1,4 +1,4 @@ -<% title 'TESING' %> +<% title t '.title' %>
@@ -6,15 +6,18 @@ <%= @crime_application.reference %>

+

+ <%= @crime_application.applicant.full_name %> +

+ +

+ <%= t '.title' %> +

+ <%= form_with model: @form_object, url: crime_application_decision_funding_decision_path(), method: :put do |f| %> - <%= f.govuk_error_summary %> - - <%= f.govuk_collection_radio_buttons :result, - @form_object.possible_results, - :to_s - %> + <%= f.govuk_collection_radio_buttons :result, @form_object.possible_results, :to_s %> <%= f.govuk_text_area :details %> <%= f.govuk_submit %> <% end %> diff --git a/app/views/casework/decisions/index.html.erb b/app/views/casework/decisions/index.html.erb index da29690d4..5db967c53 100644 --- a/app/views/casework/decisions/index.html.erb +++ b/app/views/casework/decisions/index.html.erb @@ -1,6 +1,21 @@ -<% title ':K:LKJ:LKJ:LKJ' %> -<%= render( - DecisionComponent.with_collection( - @decisions - )) %> +<% title t '.title', count: @decisions.size %> +
+
+

+ <%= @crime_application.reference %> +

+ +

+ <%= @crime_application.applicant.full_name %> +

+ +

+ <%= t '.title', count: @decisions.size %> +

+
+
+ +<%= render(DecisionComponent.with_collection(@decisions)) %> + +<%= govuk_button_to(t(:add_funding_decision, scope: 'calls_to_action')) %> diff --git a/app/views/casework/decisions/interests_of_justices/edit.html.erb b/app/views/casework/decisions/interests_of_justices/edit.html.erb index 05e6ad3f6..73f0698c5 100644 --- a/app/views/casework/decisions/interests_of_justices/edit.html.erb +++ b/app/views/casework/decisions/interests_of_justices/edit.html.erb @@ -1,4 +1,4 @@ -<% title 'TESING' %> +<% title t '.title' %>
@@ -6,6 +6,14 @@ <%= @crime_application.reference %>

+

+ <%= @crime_application.applicant.full_name %> +

+ +

+ <%= t '.title' %> +

+ <%= form_with model: @form_object, url: crime_application_decision_interests_of_justice_path(), method: :put do |f| %> diff --git a/app/views/casework/decisions/show.html.erb b/app/views/casework/decisions/show.html.erb deleted file mode 100644 index a982539ca..000000000 --- a/app/views/casework/decisions/show.html.erb +++ /dev/null @@ -1,5 +0,0 @@ -<% title ':K:LKJ:LKJ:LKJ' %> - - -<%= render @decision %> - diff --git a/config/locales/en/casework.yml b/config/locales/en/casework.yml index 9540786ca..e65641067 100644 --- a/config/locales/en/casework.yml +++ b/config/locales/en/casework.yml @@ -425,6 +425,13 @@ en: change_in_financial_circumstances: Change in financial circumstances committal: Committal for sentence deleted_user_name: '[deleted]' + decision_result: + pass: Passed + fail: Failed + granted_on_ioj: Granted + fail_on_ioj: Rejected + + either_way: Either way esa: Income-related Employment and Support Allowance (ESA) guarantee_pension: Guarantee Credit element of Pension Credit @@ -656,7 +663,6 @@ en: casework: - assigned_applications: index: page_title: Your list @@ -736,3 +742,15 @@ en: <<: *LABELS values: <<: *VALUES + decisions: + index: + title: + zero: Add a funding decision + one: Check the funding decision + other: You have added %{count} case + interests_of_justices: + edit: + title: Interests of justice test + funding_decisions: + edit: + title: Overall result diff --git a/config/routes.rb b/config/routes.rb index 9a7f47959..634437d84 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -38,11 +38,13 @@ resource :reassign, only: [:new, :create] resource :return, only: [:new, :create] post 'add_a_funding_decision', to: 'decisions#create' + post 'add_a_funding_decision', to: 'decisions#create' resources :decisions do + get :confirm_destroy, on: :member scope module: :decisions do - resource :interests_of_justice - resource :funding_decision + resource :interests_of_justice, only: [:edit, :update] + resource :funding_decision, only: [:edit, :update] end end end