diff --git a/app/controllers/publish/courses/ratifying_provider_controller.rb b/app/controllers/publish/courses/ratifying_provider_controller.rb new file mode 100644 index 0000000000..8bb974586b --- /dev/null +++ b/app/controllers/publish/courses/ratifying_provider_controller.rb @@ -0,0 +1,172 @@ +# frozen_string_literal: true + +module Publish + module Courses + class RatifyingProviderController < PublishController + include CourseBasicDetailConcern + before_action :build_course, only: %i[edit update] + before_action :build_course_params, only: :continue + helper_method :accredited_partners + + def accredited_partners + if Settings.features.provider_partnerships + @provider.accredited_partners + else + @provider.accredited_bodies + end + end + + def show + @course = build_course&.decorate + render_not_found if @course.accrediting_provider.blank? + end + + def edit + build_provider + end + + def continue + authorize(@provider, :can_create_course?) + + code = course_params[:accredited_provider_code] + query = @accredited_provider + + @errors = errors_for_search_query(code, query) + + if @errors.present? + render :new + elsif other_selected_with_no_autocompleted_code?(code) + redirect_to( + search_new_publish_provider_recruitment_cycle_courses_accredited_provider_path( + query: @accredited_provider, + course: course_params + ) + ) + else + params[:course][:accredited_provider_code] = @autocompleted_provider_code if @autocompleted_provider_code.present? + super + end + end + + def search_new + authorize(provider, :can_create_course?) + + # These are not before_action hooks as they conflict with hooks + # defined within the CourseBasicDetailConcern and cannot be overridden + # without causing failures in other routes in this controller + build_new_course + build_provider + build_previous_course_creation_params + @query = params[:query] + @provider_suggestions = recruitment_cycle.providers.with_findable_courses.provider_search(@query).limit(10) + end + + def update + build_provider + begin + code = update_course_params[:accredited_provider_code] + query = update_course_params[:accredited_provider] + rescue ActionController::ParameterMissing + @errors = errors_for_search_query(code, query) + return render :edit if @errors.present? + end + + if update_params[:accredited_provider_code] == 'other' + redirect_to_provider_search + elsif @course.update(update_params) + course_updated_message('Accredited provider') + redirect_to_update_successful + else + @errors = @course.errors.messages + render :edit + end + end + + def search + build_course + @query = params[:query] + @provider_suggestions = recruitment_cycle.providers.with_findable_courses.provider_search(@query).limit(10) + end + + private + + def build_provider + @provider = RecruitmentCycle.find_by(year: params[:recruitment_cycle_year]) + .providers + .find_by(provider_code: params[:provider_code]) + end + + def error_keys + [:accredited_provider_code] + end + + def redirect_to_provider_search + redirect_to( + accredited_provider_search_provider_recruitment_cycle_course_path( + @course.provider_code, + @course.recruitment_cycle_year, + @course.course_code, + query: update_course_params[:accredited_provider] + ) + ) + end + + def redirect_to_update_successful + redirect_to( + details_publish_provider_recruitment_cycle_course_path( + @course.provider_code, + @course.recruitment_cycle_year, + @course.course_code + ) + ) + end + + def current_step + :accredited_provider + end + + def build_course_params + @accredited_provider = params[:course].delete(:accredited_provider) + @autocompleted_provider_code = params[:course].delete(:autocompleted_provider_code) + end + + def errors_for_search_query(code, query) + errors = {} + + if other_selected_with_no_autocompleted_code?(code) && query.length < 2 + errors = { accredited_provider: ['Accredited provider search too short, enter 2 or more characters'] } + elsif code.blank? + errors = { accredited_provider_code: ['Select an accredited provider'] } + end + + errors + end + + def update_course_params + params.require(:course).permit( + :autocompleted_provider_code, + :accredited_provider_code, + :accredited_provider + ) + end + + def update_params + autocompleted_code = update_course_params[:autocompleted_provider_code] + code = update_course_params[:accredited_provider_code] + + { + accredited_provider_code: autocompleted_code.presence || code + } + end + + def other_selected_with_no_autocompleted_code?(code) + code == 'other' && @autocompleted_provider_code.blank? + end + + def build_course + super + authorize @course + end + end + end +end diff --git a/app/views/publish/courses/ratifying_provider/_provider_search_field.html.erb b/app/views/publish/courses/ratifying_provider/_provider_search_field.html.erb new file mode 100644 index 0000000000..16d4443104 --- /dev/null +++ b/app/views/publish/courses/ratifying_provider/_provider_search_field.html.erb @@ -0,0 +1,11 @@ +<%= render "publish/shared/error_wrapper", error_keys: [:accredited_provider], data_qa: "course__provider_search" do %> + <%= form.label :accredited_provider, + for: "course_accredited_provider", + class: "govuk-label" do %> + Enter the provider name or code <%= render "publish/shared/error_messages", error_keys: [:accredited_provider] %> + <% end %> + <%= form.text_field :accredited_provider, + autocomplete: "off", + class: "govuk-input govuk-!-width-two-thirds" %> +
+<% end %> diff --git a/app/views/publish/courses/ratifying_provider/_provider_suggestion.html.erb b/app/views/publish/courses/ratifying_provider/_provider_suggestion.html.erb new file mode 100644 index 0000000000..c8d347af03 --- /dev/null +++ b/app/views/publish/courses/ratifying_provider/_provider_suggestion.html.erb @@ -0,0 +1,10 @@ +
+ <%= form.radio_button :accredited_provider_code, + provider_suggestion[:provider_code], + checked: provider_suggestion[:provider_code] == @course.accrediting_provider&.provider_code, + class: "govuk-radios__input" %> + <%= form.label :accredited_provider_code, + provider_suggestion[:provider_name], + value: provider_suggestion[:provider_code], + class: "govuk-label govuk-radios__label" %> +
diff --git a/app/views/publish/courses/ratifying_provider/edit.html.erb b/app/views/publish/courses/ratifying_provider/edit.html.erb new file mode 100644 index 0000000000..f7a7c807a0 --- /dev/null +++ b/app/views/publish/courses/ratifying_provider/edit.html.erb @@ -0,0 +1,43 @@ +<% content_for :page_title, title_with_error_prefix("Ratifying provider – #{course.name_and_code}", course.errors.any?) %> + +<% content_for :before_content do %> + <%= govuk_back_link_to(details_publish_provider_recruitment_cycle_course_path(course.provider_code, course.recruitment_cycle_year, course.course_code)) %> +<% end %> + +<%= render "publish/shared/errors" %> + +
+ +

+ <%= render CaptionText.new(text: course.name_and_code) %> + Ratifying provider +

+
+ +
+
+ <%= form_with model: course, + url: ratifying_provider_publish_provider_recruitment_cycle_course_path(@course.provider_code, @course.recruitment_cycle_year, @course.course_code), + method: :put do |form| %> + +
+ <%= render partial: "provider_suggestion", collection: accredited_partners, locals: { form: } %> +
+ +
+ <%= form.submit "Update ratifying partner", class: "govuk-button govuk-!-margin-top-5", data: { qa: "course__save" } %> + <%= govuk_link_to( + "Add accredited partner", + search_publish_provider_recruitment_cycle_accredited_providers_path(course.provider_code, course.recruitment_cycle_year), + class: "govuk-!-margin-bottom-6 govuk-!-margin-top-5", + data: { qa: "course__add" } + ) %> +
+ <% end %> + +

+ <%= govuk_link_to(t("cancel"), details_publish_provider_recruitment_cycle_course_path(@provider.provider_code, @provider.recruitment_cycle_year)) %> +

+
+
+
diff --git a/app/views/publish/courses/ratifying_provider/new.html.erb b/app/views/publish/courses/ratifying_provider/new.html.erb new file mode 100644 index 0000000000..163b73fca3 --- /dev/null +++ b/app/views/publish/courses/ratifying_provider/new.html.erb @@ -0,0 +1,39 @@ +<% content_for :page_title, title_with_error_prefix("Accredited provider – #{course.name_and_code}", @errors && @errors.any?) %> + +<% content_for :before_content do %> + <%= govuk_back_link_to(@back_link_path) %> +<% end %> + +<%= render "publish/shared/errors" %> +
+
+ <%= form_with url: continue_publish_provider_recruitment_cycle_courses_accredited_provider_path(@provider.provider_code, @provider.recruitment_cycle_year), method: :get do |form| %> + <%= render "publish/courses/new_fields_holder", form:, except_keys: [:accredited_provider_code] do |fields| %> + <%= render "publish/shared/error_wrapper", error_keys: [:accredited_provider_code], data_qa: "course__accredited_provider" do %> +
+ +

+ <%= render CaptionText.new(text: t("course.add_course")) %> + Accredited provider +

+
+ <%= render "publish/shared/error_messages", error_keys: [:accredited_provider_code] %> + +
+ <% if @provider.accredited_bodies.length > 0 %> + <%= render partial: "provider_suggestion", collection: @provider.accredited_bodies.sort_by { |k| k[:provider_name] }, locals: { form: fields } %> + <% else %> + <%= fields.hidden_field :accredited_provider_code, value: :other %> + <%= render "provider_search_field", form: fields %> + <% end %> +
+ <% end %> + <% end %> +

+ <%= govuk_link_to(t("cancel"), publish_provider_recruitment_cycle_courses_path(@provider.provider_code, @provider.recruitment_cycle_year)) %> +

+
+ + <% end %> +
+ diff --git a/app/views/publish/courses/ratifying_provider/search.html.erb b/app/views/publish/courses/ratifying_provider/search.html.erb new file mode 100644 index 0000000000..4e3c6e27b9 --- /dev/null +++ b/app/views/publish/courses/ratifying_provider/search.html.erb @@ -0,0 +1,57 @@ +<% content_for :page_title, title_with_error_prefix("Organisation search", course.errors.any?) %> + +<% content_for :before_content do %> + <%= govuk_back_link_to(details_provider_recruitment_cycle_course_path(course.provider_code, course.recruitment_cycle_year, course.course_code)) %> +<% end %> + +<%= render "publish/shared/errors" %> + +
+
+

+ Pick an accredited provider +

+ +

You searched for ‘<%= @query %>’.

+ + <%= form_with model: course, + url: accredited_provider_provider_recruitment_cycle_course_path(params[:provider_code], params[:recruitment_cycle_year], params[:code]), + method: :put do |form| %> + + <% if @provider_suggestions.any? %> +

We found these providers which matched your search:

+ +
+ <%= render partial: "provider_suggestion", collection: @provider_suggestions, locals: { form: } %> +
or
+ +
+ <%= form.radio_button :accredited_provider_code, + "other", + class: "govuk-radios__input", + data: { "aria-controls" => "other-container" } %> + <%= form.label :accredited_provider_code, + "Try another accrediting provider", + for: "course_accredited_provider_code_other", + value: false, + class: "govuk-label govuk-radios__label" %> +
+ +
+ <%= render "provider_search_field", form: %> +
+
+ <% else %> +

We did not find any accredited bodies which matched your search.

+ +

Try another search:

+ + <%= form.hidden_field :accredited_provider_code, value: :other %> + <%= render "provider_search_field", form: %> + <% end %> + + <%= form.submit course.is_running? ? "Save and publish changes" : "Save", + class: "govuk-button govuk-!-margin-top-3", data: { qa: "course__save" } %> + <% end %> +
+
diff --git a/app/views/publish/courses/ratifying_provider/search_new.html.erb b/app/views/publish/courses/ratifying_provider/search_new.html.erb new file mode 100644 index 0000000000..1d11bc2dc2 --- /dev/null +++ b/app/views/publish/courses/ratifying_provider/search_new.html.erb @@ -0,0 +1,61 @@ +<% content_for :page_title, title_with_error_prefix("Organisation search", course.errors.any?) %> + +<%= render "publish/shared/errors" %> + +
+
+

+ Pick an accredited provider +

+ +

You searched for ‘<%= @query %>’.

+ + <%= form_with model: course, + url: continue_publish_provider_recruitment_cycle_courses_accredited_provider_path( + @provider.provider_code, + @provider.recruitment_cycle_year + ), + method: :get do |form| %> + + <%= render "publish/shared/course_creation_hidden_fields", + form:, + course_creation_params: @course_creation_params, + except_keys: [:accredited_provider_code] %> + + <% if @provider_suggestions.any? %> +

We found these providers which matched your search:

+ +
+ <%= render partial: "provider_suggestion", collection: @provider_suggestions, locals: { form: } %> +
or
+ +
+ <%= form.radio_button :accredited_provider_code, + "other", + class: "govuk-radios__input", + data: { "aria-controls" => "other-container" } %> + <%= form.label :accredited_provider_code, + "Try another accrediting provider", + for: "course_accredited_provider_code_other", + value: false, + class: "govuk-label govuk-radios__label" %> +
+ +
+ <%= render "provider_search_field", form: %> +
+
+ <% else %> +

We did not find any accredited bodies which matched your search.

+ +

Try another search:

+ + <%= form.hidden_field :accredited_provider_code, value: :other %> + <%= render "provider_search_field", form: %> + <% end %> + + <%= form.submit course.is_running? ? "Save and publish changes" : "Save", + class: "govuk-button govuk-!-margin-top-3", data: { qa: "course__save" } %> + <% end %> +
+
diff --git a/app/views/publish/courses/ratifying_provider/show.html.erb b/app/views/publish/courses/ratifying_provider/show.html.erb new file mode 100644 index 0000000000..e10e5ae934 --- /dev/null +++ b/app/views/publish/courses/ratifying_provider/show.html.erb @@ -0,0 +1,26 @@ +<%= content_for :page_title do %> + <%= t( + "publish.providers.courses.accredited_provider.show.heading", + provider_name: @course.accrediting_provider + ) %> +<% end %> +<% content_for :before_content do %> + <%= govuk_back_link( + href: preview_publish_provider_recruitment_cycle_course_path( + @course.provider_code, + @course.recruitment_cycle_year, + @course.course_code + ), + text: t( + "publish.providers.courses.accredited_provider.show.back", + course_name: @course.name, + course_code: @course.course_code + ) + ) %> +<% end %> + +
+
+ <%= render partial: "find/courses/about_accrediting_provider", locals: { course: @course } %> +
+
diff --git a/spec/features/publish/courses/adding_a_ratifying_provider_to_an_unpublished_course_spec.rb b/spec/features/publish/courses/adding_a_ratifying_provider_to_an_unpublished_course_spec.rb new file mode 100644 index 0000000000..283e2a9968 --- /dev/null +++ b/spec/features/publish/courses/adding_a_ratifying_provider_to_an_unpublished_course_spec.rb @@ -0,0 +1,120 @@ +# frozen_string_literal: true + +require 'rails_helper' + +feature 'unpublished course without accredited provider', { can_edit_current_and_next_cycles: false } do + before do + allow(Settings.features).to receive(:provider_partnerships).and_return(true) + end + + scenario 'adding and changing an accredited provider' do + given_i_am_authenticated_as_a_provider_user + and_i_visit_the_course_details_page_of_a_course_without_an_accredited_provider + and_i_click_the_add_accredited_provider_link + and_i_create_a_new_accredited_provider + and_i_revisit_the_course_details_page + when_i_click_select_an_accredited_provider + and_i_choose_the_new_accredited_provider + then_i_should_see_the_success_message + + given_i_click_change_accredited_provider + and_i_click_update_accredited_provider + then_i_should_see_the_success_message + end + + def given_i_click_change_accredited_provider + click_link_or_button 'Change accredited provider' + end + + def then_i_should_see_the_success_message + expect(page).to have_text('Accredited provider updated') + end + + def and_i_click_update_accredited_provider + click_link_or_button 'Update ratifying partner' + end + + def and_i_choose_the_new_accredited_provider + choose @accredited_provider.provider_name + and_i_click_update_accredited_provider + end + + def when_i_click_select_an_accredited_provider + click_link_or_button 'Select an accredited partner' + end + + def and_i_create_a_new_accredited_provider + and_there_is_an_accredited_provider_in_the_database + and_i_click_add_accredited_provider_link + and_i_search_for_an_accredited_provider_with_a_valid_query + and_i_select_the_provider + and_i_input_some_information + and_i_click_add_accredited_provider_button + end + + def and_i_select_the_provider + choose @accredited_provider.provider_name + click_continue + end + + def and_i_input_some_information + fill_in 'About the accredited partner', with: 'This is a description' + click_continue + end + + def and_there_is_an_accredited_provider_in_the_database + @accredited_provider = create(:provider, :accredited_provider, provider_name: 'UCL') + end + + def and_i_search_for_an_accredited_provider_with_a_valid_query + fill_in form_title, with: @accredited_provider.provider_name + click_continue + end + + def click_continue + click_link_or_button 'Continue' + end + + def form_title + 'Enter a provider name, UKPRN or postcode' + end + + def and_i_click_the_add_accredited_provider_link + click_link_or_button 'Add at least one accredited partner' + end + + def and_i_click_add_accredited_provider_link + click_link_or_button 'Add accredited partner' + end + + def and_i_click_add_accredited_provider_button + click_link_or_button 'Add accredited partner' + end + + def given_i_am_authenticated_as_a_provider_user + given_i_am_authenticated( + user: create( + :user, + providers: [ + create(:provider, sites: [build(:site)], courses: [build(:course)]) + ] + ) + ) + end + + def and_i_visit_the_course_details_page_of_a_course_without_an_accredited_provider + publish_provider_courses_details_page.load( + provider_code: provider.provider_code, recruitment_cycle_year: provider.recruitment_cycle_year, course_code: course.course_code + ) + end + + alias_method :and_i_revisit_the_course_details_page, :and_i_visit_the_course_details_page_of_a_course_without_an_accredited_provider + + def provider + @current_user.providers.first + end + + def course + provider.courses.first + end +end