Skip to content

Commit

Permalink
feat(fworks): evaluation workflows
Browse files Browse the repository at this point in the history
  • Loading branch information
ryantk committed Nov 22, 2023
1 parent 0411ec9 commit f8a598b
Show file tree
Hide file tree
Showing 24 changed files with 228 additions and 44 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

class ActivityLog::Types::EmailsMovedFromComponent < ViewComponent::Base
class ActivityLog::Types::Frameworks::Evaluation::EmailsMovedFromComponent < ViewComponent::Base
include ActivityLog::Types::BasicActivityDetails

def initialize(activity_log_item:)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class ActivityLog::Types::EvaluationTransferredComponent < ViewComponent::Base
class ActivityLog::Types::Frameworks::Evaluation::EvaluationTransferredComponent < ViewComponent::Base
include ActivityLog::Types::BasicActivityDetails

def initialize(activity_log_item:)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<%= render ActivityLog::HistoryItemComponent.new(by:, date:) do |component| %>
<% component.with_title do %>
Evaluation approved: <%= link_to evaluation_reference, evaluation, class: "govuk-link", "data-turbo" => false %>
<% end %>
<% end %>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

class ActivityLog::Types::Frameworks::Framework::EvaluationApprovedComponent < ViewComponent::Base
include ActivityLog::Types::BasicActivityDetails

def initialize(activity_log_item:)
@activity_log_item = activity_log_item
end

def evaluation
Frameworks::Evaluation.find(@activity_log_item.activity.data["evaluation_id"])
end

delegate :reference, to: :evaluation, prefix: true
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<%= render ActivityLog::HistoryItemComponent.new(by:, date:) do |component| %>
<% component.with_title do %>
Evaluation created: <%= link_to evaluation_reference, evaluation, class: "govuk-link", "data-turbo" => false %>
<% end %>
<% end %>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

class ActivityLog::Types::Frameworks::Framework::EvaluationCreatedComponent < ViewComponent::Base
include ActivityLog::Types::BasicActivityDetails

def initialize(activity_log_item:)
@activity_log_item = activity_log_item
end

def evaluation
Frameworks::Evaluation.find(@activity_log_item.activity.data["evaluation_id"])
end

delegate :reference, to: :evaluation, prefix: true
end
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

class ActivityLog::Types::EvaluationStartedComponent < ViewComponent::Base
class ActivityLog::Types::Frameworks::Framework::EvaluationStartedComponent < ViewComponent::Base
include ActivityLog::Types::BasicActivityDetails

def initialize(activity_log_item:)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<tr class="govuk-table__row">
<th scope="row" class="govuk-table__header"><%= changes.field.humanize %></th>
<td class="govuk-table__cell">
<% unless @activity_log_item.subject_type.demodulize == "create" %>
<% unless @activity_log_item.activity.event == "create" %>
<%= true_false_or_empty[changes.from] %>
<span class="activity-log-change-arrow"></span>
<% end %>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,6 @@ def quick_edit_params
end

def form_params
params.require(:quick_edit).permit(:note, :next_key_date, :next_key_date_description)
params.require(:quick_edit).permit(:note, :next_key_date, :next_key_date_description, :status)
end
end
5 changes: 5 additions & 0 deletions app/models/frameworks/evaluation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,9 @@ class Frameworks::Evaluation < ApplicationRecord
belongs_to :contact, class_name: "Frameworks::ProviderContact", optional: true

alias_attribute :ref, :reference

before_save do
# prevent activity log items for "none"-changes
self.next_key_date_description = nil if changes.key?(:next_key_date_description) && next_key_date_description == ""
end
end
4 changes: 3 additions & 1 deletion app/models/frameworks/evaluation/noteable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ module Frameworks::Evaluation::Noteable
extend ActiveSupport::Concern

def add_note(note)
log_activity_event("note_added", body: note)
if note.present? && note != latest_note.try(:body)
log_activity_event("note_added", body: note)
end
end

def latest_note
Expand Down
21 changes: 16 additions & 5 deletions app/models/frameworks/evaluation/quick_editable.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
module Frameworks::Evaluation::QuickEditable
extend ActiveSupport::Concern

def quick_editor(note: latest_note&.body, next_key_date: self.next_key_date, next_key_date_description: self.next_key_date_description)
Frameworks::Evaluation::QuickEditor.new(frameworks_evaluation: self, note:, next_key_date:, next_key_date_description:)
def quick_editor(
note: latest_note.try(:body),
next_key_date: self.next_key_date,
next_key_date_description: self.next_key_date_description,
status: self.status
)
Frameworks::Evaluation::QuickEditor.new(
frameworks_evaluation: self,
note:,
next_key_date:,
next_key_date_description:,
status:,
)
end

def quick_edit(details)
def quick_edit(details = {})
transaction do
update!(details.except(:note)) if details[:next_key_date_description].present?
add_note(details[:note]) if details[:note].present? && details[:note] != latest_note&.body
update!(details.except(:note)) if details.except(:note).any?
add_note(details[:note])
end
end
end
3 changes: 2 additions & 1 deletion app/models/frameworks/evaluation/quick_editor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ class Frameworks::Evaluation::QuickEditor
attribute :note
attribute :next_key_date
attribute :next_key_date_description
attribute :status

def save!
frameworks_evaluation.quick_edit(note:, next_key_date:, next_key_date_description:)
frameworks_evaluation.quick_edit(note:, next_key_date:, next_key_date_description:, status:)
end
end
43 changes: 39 additions & 4 deletions app/models/frameworks/evaluation/status_changeable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ module Frameworks::Evaluation::StatusChangeable
included do
include AASM

after_create_commit :after_drafting_of_evaluation, if: :draft?

before_save :call_permissable_event_for_manual_updates, if: -> { status_changed? && (aasm.from_state.nil? || aasm.to_state.nil?) }

enum status: {
draft: 0,
in_progress: 1,
Expand All @@ -15,26 +19,44 @@ module Frameworks::Evaluation::StatusChangeable
aasm column: :status, enum: true do
Frameworks::Evaluation.statuses.each { |status, _| state status.to_sym }

event :start do
event :mark_as_in_progress do
transitions from: :draft, to: :in_progress, after: :after_starting_evaluation
end

event :approve do
event :mark_as_approved do
transitions from: :in_progress, to: :approved, after: :after_approving
end

event :disapprove do
event :mark_as_not_approved do
transitions from: :in_progress, to: :not_approved, after: :after_disapproving
end

event :cancel do
event :mark_as_cancelled do
transitions from: :in_progress, to: :cancelled, after: :after_cancelling
end
end
end

def permissible_status_change_options(prepend_current_status: false)
option_for_status = ->(status) { self.class.aasm.states_for_select.find { |select| select.last == status.to_s } }

options = aasm.permitted_transitions.map do |transition|
option_for_status.call(transition[:state])
end

prepend_current_status ? options.prepend(option_for_status.call(status)) : options
end

def able_to_change_status?
permissible_status_change_options.any?
end

private

def after_drafting_of_evaluation
framework.draft_evaluation!(self)
end

def after_starting_evaluation
framework.start_evaluation!(self)
end
Expand All @@ -50,4 +72,17 @@ def after_disapproving
def after_cancelling
framework.cancel_evaluation!(self)
end

def call_permissable_event_for_manual_updates
from_status, to_status = changes["status"]

# Set AASM to the status we have changed from (it is currently empty)
aasm.current_state = from_status

# Find the event we would have manually fired for the same effect
transition_for_status_change = aasm.permitted_transitions.find { |transition| transition[:state] == to_status.to_sym }

# Fire the event to ensure our callbacks are triggered
aasm.fire(transition_for_status_change[:event]) if aasm.may_fire_event?(transition_for_status_change[:event])
end
end
14 changes: 11 additions & 3 deletions app/models/frameworks/framework/status_changeable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,20 @@ module Frameworks::Framework::StatusChangeable
include AASM

enum status: {
pending_evaluation: 0,
evaluating: 1,
not_approved: 2,
not_approved: 0,
pending_evaluation: 1,
evaluating: 2,
dfe_approved: 3,
cab_approved: 4,
}

aasm column: :status, enum: true do
Frameworks::Framework.statuses.each { |status, _| state status.to_sym }

event :draft_evaluation do
transitions from: %i[not_approved], to: :pending_evaluation, after: :after_drafting_evaluation
end

event :start_evaluation do
transitions from: %i[pending_evaluation not_approved], to: :evaluating, after: :after_starting_evaluation
end
Expand All @@ -35,6 +39,10 @@ module Frameworks::Framework::StatusChangeable

private

def after_drafting_evaluation(evaluation)
log_activity_event("evaluation_drafted", evaluation_id: evaluation.id)
end

def after_starting_evaluation(evaluation)
log_activity_event("evaluation_started", evaluation_id: evaluation.id)
end
Expand Down
11 changes: 10 additions & 1 deletion app/views/frameworks/evaluations/quick_edits/edit.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

<div class="govuk-grid-row">
<div class="govuk-grid-column-one-third">
<h1 class="govuk-heading-l"><%= I18n.t("frameworks.evaluation.quick_edit.header", reference: @evaluation.reference) %></h1>
<span class="govuk-caption-l">[<%= @evaluation.reference %>] Framework Evaluation</span>
<h1 class="govuk-heading-l">Quick Edit</h1>

<%= form_with model: @quick_edit,
scope: :quick_edit,
url: frameworks_evaluation_quick_edit_path(back_to: Base64.encode64(@back_url), redirect_back: params[:redirect_back]),
Expand All @@ -13,6 +15,13 @@

<%= render "support/cases/components/next_key_date", form: form %>

<% if @evaluation.able_to_change_status? %>
<%= form.govuk_collection_radio_buttons :status, @evaluation.permissible_status_change_options(prepend_current_status: true), :last, :first, small: true, legend: { text: "Update status (optional)" }, hint: { text: "Current status: #{@evaluation.status.humanize}" } %>
<% else %>

<p class="govuk-body">NOTE: Status select options disabled as current status "<%= @evaluation.status.humanize %>" is the final status.</p>
<% end %>

<div class="govuk-button-group">
<%= form.submit I18n.t("generic.button.save"), class: "govuk-button", role: "button" %>
<%= link_to "Exit without saving", @back_url, class: "govuk-link govuk-link--no-visited-state" %>
Expand Down
2 changes: 1 addition & 1 deletion app/views/frameworks/evaluations/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@

<h2 class="govuk-heading-m">Actions</h2>
<ul class="govuk-list">
<li><%= link_to "Quick edit", edit_frameworks_evaluation_quick_edit_path(@evaluation, back_to: current_url_b64, redirect_back: current_url_b64), class: "govuk-link govuk-link--no-visited-state", "target" => "_top" %></li>
<li><%= govuk_link_to "Quick edit", edit_frameworks_evaluation_quick_edit_path(@evaluation, back_to: current_url_b64, redirect_back: current_url_b64), "target" => "_top" %></li>
</ul>
</div>

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
describe "Agent can create new framework evaluations", js: true do
include_context "with a framework evaluation agent"

let(:framework) { create(:frameworks_framework, status: "pending_evaluation") }
let(:framework) { create(:frameworks_framework) }

it "can create a new evaluation from the framework" do
visit frameworks_framework_path(framework)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,16 @@
fill_in "Month", with: "08"
fill_in "Year", with: "2023"
fill_in "Description of next key date", with: "Key event"
choose "In progress"
click_button "Save"
end

it "persists the changes" do
framework_evaluation.reload
expect(framework_evaluation.latest_note.body).to eq("New note")
expect(framework_evaluation.reload.next_key_date).to eq(Date.parse("2023-08-10"))
expect(framework_evaluation.reload.next_key_date_description).to eq("Key event")
expect(framework_evaluation.next_key_date).to eq(Date.parse("2023-08-10"))
expect(framework_evaluation.next_key_date_description).to eq("Key event")
expect(framework_evaluation.status).to eq("in_progress")
end
end
end
Loading

0 comments on commit f8a598b

Please sign in to comment.