-
Notifications
You must be signed in to change notification settings - Fork 3
[3130] Void declarations in the admin console #2251
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
ae22f17
ab05ddd
bdc2eb9
4511520
4fe407e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| module Admin | ||
| module Finance | ||
| class VoidsController < Admin::Finance::BaseController | ||
| layout "full" | ||
|
|
||
| before_action :set_declaration | ||
| before_action :set_teacher | ||
| before_action :set_void_declaration_form | ||
|
|
||
| def new | ||
| end | ||
|
|
||
| def create | ||
| if @void_declaration_form.void! | ||
| flash[:alert] = "Declaration voided" | ||
| redirect_to admin_teacher_declarations_path(@teacher) | ||
| else | ||
| render :new, status: :unprocessable_content | ||
| end | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def set_declaration | ||
| @declaration = Declaration.find(params[:declaration_id]) | ||
| end | ||
|
|
||
| def set_teacher | ||
| @teacher = @declaration.teacher | ||
| end | ||
|
|
||
| def set_void_declaration_form | ||
| @void_declaration_form = VoidDeclarationForm.new( | ||
| declaration: @declaration, | ||
| author: current_user, | ||
| **void_declaration_form_params | ||
| ) | ||
| end | ||
|
|
||
| def void_declaration_form_params | ||
| return {} unless params.key?(:admin_finance_void_declaration_form) | ||
|
|
||
| params.expect(admin_finance_void_declaration_form: [:confirmed]) | ||
| end | ||
| end | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| module Admin | ||
| module Finance | ||
| class VoidDeclarationForm | ||
| include ActiveModel::Model | ||
| include ActiveModel::Attributes | ||
|
|
||
| attribute :declaration | ||
| attribute :author | ||
| attribute :confirmed, :boolean | ||
|
|
||
| validates :confirmed, acceptance: { message: "Confirm you want to void this declaration", allow_nil: false } | ||
|
|
||
| validate :clawback_statement_available, if: :paid_declaration? | ||
|
|
||
| def void! | ||
| return false unless valid? | ||
|
|
||
| if paid_declaration? | ||
| clawback_service.clawback | ||
| else | ||
| void_service.void | ||
| end | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def paid_declaration? | ||
| declaration&.payment_status_paid? | ||
| end | ||
|
|
||
| def clawback_statement_available | ||
| return if clawback_service.next_available_output_fee_statement.present? | ||
|
|
||
| errors.add(:base, "This declaration has been paid, and no future statement exists for clawback") | ||
| end | ||
|
|
||
| def clawback_service | ||
| @clawback_service ||= Declarations::Clawback.new(**service_attributes) | ||
| end | ||
|
|
||
| def void_service | ||
| @void_service ||= Declarations::Void.new(**service_attributes) | ||
| end | ||
|
|
||
| def service_attributes | ||
| { | ||
| author:, | ||
| declaration:, | ||
| voided_by_user_id: author&.id | ||
| } | ||
| end | ||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -44,4 +44,16 @@ def declaration_course_identifier(declaration) | |
| "ecf-mentor" | ||
| end | ||
| end | ||
|
|
||
| def declaration_voided_by_caption(declaration, event) | ||
| return unless event.event_type.in?(%w[teacher_declaration_voided teacher_declaration_clawed_back]) | ||
|
|
||
| text = if declaration.voided_by_user.present? | ||
| "Voided by #{declaration.voided_by_user.name} (#{declaration.voided_by_user.email})" | ||
| else | ||
| "Voided by lead provider" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since the row is "Clawed back", should the caption read "Clawed back by..." instead of "Voided by..."? At the moment the wording is inconsistent, it reads a bit off to me. Did you have any thoughts on that?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah I had a similar thought 🤔 I can see the argument either way, but concluded that the verb/action/button the user took is to void the declaration, and clawback is something the system does in certain situations, but either way the declaration is still indeed voided. So since voided isn't wrong, IMO it's fine to defer to the design on this one. |
||
| end | ||
|
|
||
| tag.span(text, class: "govuk-caption-m") | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| <% page_data( | ||
| title: "Void declaration for #{teacher_full_name(@teacher)}", | ||
| backlink_href: admin_teacher_declarations_path(@teacher) | ||
| ) %> | ||
|
|
||
| <div class="govuk-grid-row"> | ||
| <div class="govuk-grid-column-full"> | ||
| <%= | ||
| govuk_summary_list(actions: false) do |summary_list| | ||
| summary_list.with_row do |row| | ||
| row.with_key { "Declaration ID" } | ||
| row.with_value { tag.span(@declaration.api_id, class: "app-mono") } | ||
| end | ||
|
|
||
| summary_list.with_row do |row| | ||
| row.with_key { "Course identifier" } | ||
| row.with_value { tag.span(declaration_course_identifier(@declaration), class: "app-mono") } | ||
| end | ||
|
|
||
| summary_list.with_row do |row| | ||
| row.with_key { "Declaration type" } | ||
| row.with_value { tag.span(@declaration.declaration_type, class: "app-mono") } | ||
| end | ||
|
|
||
| summary_list.with_row do |row| | ||
| row.with_key { "State" } | ||
| row.with_value { declaration_state_tag(@declaration) } | ||
| end | ||
|
|
||
| summary_list.with_row do |row| | ||
| row.with_key { "Declaration date and time" } | ||
| row.with_value { @declaration.declaration_date.to_fs(:govuk) } | ||
| end | ||
|
|
||
| summary_list.with_row do |row| | ||
| row.with_key { "Lead provider" } | ||
| row.with_value { @declaration.lead_provider&.name } | ||
| end | ||
|
|
||
| summary_list.with_row do |row| | ||
| row.with_key { "Delivery partner" } | ||
| row.with_value { @declaration.delivery_partner_when_created&.name || "Delivery partner not recorded" } | ||
| end | ||
|
|
||
| summary_list.with_row do |row| | ||
| row.with_key { "Evidence held" } | ||
| row.with_value { tag.span(@declaration.evidence_type, class: "app-mono") } | ||
| end | ||
| end | ||
| %> | ||
|
|
||
| <%= form_with model: @void_declaration_form, url: admin_declaration_voids_path(@declaration), method: :post do |f| %> | ||
| <%= content_for(:error_summary) { f.govuk_error_summary } %> | ||
|
|
||
| <%= f.govuk_check_boxes_fieldset :confirmed, multiple: false, legend: nil do %> | ||
| <%= f.govuk_check_box(:confirmed, "1", false, link_errors: true, multiple: false, label: { | ||
| text: "I confirm I want to void this declaration and I understand that it cannot be undone" | ||
| }) %> | ||
| <% end %> | ||
|
|
||
| <%= f.govuk_submit "Confirm void declaration", warning: true, class: "govuk-!-margin-top-6" %> | ||
| <% end %> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we want a "Cancel and return..." link here?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is one in the ticket screenshot, but it's not there when I click through to the prototype, so looks like there was a decision to remove it. |
||
| </div> | ||
| </div> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| RSpec.describe "Void a declaration" do | ||
| before { sign_in_as_dfe_user(role: :finance) } | ||
|
|
||
| scenario "Void an unpaid declaration" do | ||
| given_a_declaration_exists | ||
| and_a_future_output_fee_statement_exists | ||
|
|
||
| when_i_visit_the_teacher_declarations_page | ||
| and_i_click_void_declaration | ||
| then_i_see_the_confirmation_page | ||
|
|
||
| when_i_click_confirm_void_declaration | ||
| then_i_see_the_success_message | ||
| and_the_declaration_is_voided | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def given_a_declaration_exists | ||
| @declaration = FactoryBot.create(:declaration, :no_payment) | ||
| @teacher = @declaration.teacher | ||
| end | ||
|
|
||
| def and_a_future_output_fee_statement_exists | ||
| active_lead_provider = FactoryBot.create(:active_lead_provider, lead_provider: @declaration.training_period.lead_provider, contract_period: @declaration.training_period.contract_period) | ||
| FactoryBot.create(:statement, :output_fee, active_lead_provider:) | ||
| end | ||
|
|
||
| def when_i_visit_the_teacher_declarations_page | ||
| page.goto(admin_teacher_declarations_path(@teacher)) | ||
| end | ||
|
|
||
| def and_i_click_void_declaration | ||
| page.locator("summary").get_by_text(@declaration.api_id).click | ||
| page.get_by_role("link", name: "Void declaration").click | ||
| end | ||
|
|
||
| def then_i_see_the_confirmation_page | ||
| expect(page.get_by_text("Void declaration for")).to be_visible | ||
| expect(page.get_by_text(@declaration.api_id)).to be_visible | ||
| expect(page.get_by_role("button", name: "Confirm void declaration")).to be_visible | ||
| end | ||
|
|
||
| def when_i_click_confirm_void_declaration | ||
| page.get_by_label("I confirm I want to void this declaration").check | ||
| page.get_by_role("button", name: "Confirm void declaration").click | ||
| end | ||
|
|
||
| def then_i_see_the_success_message | ||
| expect(page.get_by_text("Declaration voided")).to be_visible | ||
| end | ||
|
|
||
| def and_the_declaration_is_voided | ||
| expect(@declaration.reload.payment_status).to eq("voided") | ||
| end | ||
| end |
Uh oh!
There was an error while loading. Please reload this page.