diff --git a/app/components/add_course_button_partnerships.html.erb b/app/components/add_course_button_partnerships.html.erb new file mode 100644 index 0000000000..beaa855073 --- /dev/null +++ b/app/components/add_course_button_partnerships.html.erb @@ -0,0 +1,23 @@ +<% if required_organisation_details_present? %> + <%= govuk_button_link_to( + "Add course", + new_publish_provider_recruitment_cycle_course_path( + provider_code: provider.provider_code, + recruitment_cycle_year: provider.recruitment_cycle_year + ), + class: "govuk-!-margin-bottom-6" + ) %> + +<% else %> + +
+

Before adding a course, you need to:

+ +
+<% end %> diff --git a/app/components/add_course_button_partnerships.rb b/app/components/add_course_button_partnerships.rb new file mode 100644 index 0000000000..5a39e807d8 --- /dev/null +++ b/app/components/add_course_button_partnerships.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +class AddCourseButtonPartnerships < ViewComponent::Base + include RecruitmentCycleHelper + attr_reader :provider + + Section = Struct.new(:name, :path, keyword_init: true) + + def initialize(provider:) + @provider = provider + super + end + + private + + def incomplete_sections + incomplete_sections_hash.keys.select { |section| send(section) }.map do |section| + Section.new(name: "add #{incomplete_section_article(section)} #{incomplete_section_label_suffix(section)}", path: incomplete_sections_hash[section]) + end + end + + def incomplete_sections_hash + { + site_not_present?: publish_provider_recruitment_cycle_schools_path(provider.provider_code, provider.recruitment_cycle_year), + accredited_partner_not_present?: publish_provider_recruitment_cycle_accredited_partnerships_path(provider.provider_code, provider.recruitment_cycle_year) + } + end + + def incomplete_section_label_suffix(section) + labels = { + accredited_partner_not_present?: 'accredited partner', + site_not_present?: 'school' + } + + labels[section] + end + + def required_organisation_details_present? + accredited_partner_present? && site_present? + end + + def accredited_partner_present? + return true if accredited_provider? + + provider.accredited_partners.any? + end + + def site_present? + provider.sites.any? + end + + def accredited_partner_not_present? + return false if provider.accredited_provider? + + !accredited_partner_present? + end + + def site_not_present? + !site_present? + end + + def accredited_provider? + provider.accredited_provider? + end + + def incomplete_section_article(section) + incomplete_section_label_suffix(section) == 'accredited partner' ? 'an' : 'a' + end +end 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..e508c03e9c --- /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 < ApplicationController + 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/controllers/publish/providers/accredited_partnerships/checks_controller.rb b/app/controllers/publish/providers/accredited_partnerships/checks_controller.rb new file mode 100644 index 0000000000..0a2543d8b9 --- /dev/null +++ b/app/controllers/publish/providers/accredited_partnerships/checks_controller.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module Publish + module Providers + module AccreditedPartnerships + class ChecksController < ApplicationController + def show + provider_partnership_form + end + + def update + @partnership = provider.accredited_partnerships.build(accredited_provider: provider_partnership_form.accredited_provider, description: provider_partnership_form.description) + + if @partnership.save + notify_accredited_provider_users + + redirect_to publish_provider_recruitment_cycle_accredited_partnerships_path(@provider.provider_code, @provider.recruitment_cycle_year), flash: { success: 'Accredited partnership added' } + else + render :show + end + end + + private + + def provider_partnership_form + @provider_partnership_form ||= ProviderPartnershipForm.new(current_user, provider) + end + + def notify_accredited_provider_users + @partnership.accredited_provider.users.each do |user| + ::Users::OrganisationMailer.added_as_an_organisation_to_training_partner( + recipient: user, + provider: provider, + accredited_provider: @partnership.accredited_provider + ).deliver_later + end + end + end + end + end +end diff --git a/app/controllers/publish/providers/accredited_partnerships_controller.rb b/app/controllers/publish/providers/accredited_partnerships_controller.rb new file mode 100644 index 0000000000..326a5d7cdf --- /dev/null +++ b/app/controllers/publish/providers/accredited_partnerships_controller.rb @@ -0,0 +1,79 @@ +# frozen_string_literal: true + +module Publish + module Providers + class AccreditedPartnershipsController < ApplicationController + helper_method :accredited_provider_id + + def index; end + + def new + provider_partnership = provider.accredited_partnerships.build + @provider_partnership_form = ProviderPartnershipForm.new(current_user, provider_partnership, params: { accredited_provider_id: params[:accredited_provider_id] }) + end + + def edit + provider_partnership = provider.accredited_partnerships.find_by(accredited_provider: partner) + + params = { accredited_provider_id: partner.id, description: provider_partnership.description } + @provider_partnership_form = ProviderPartnershipForm.new(current_user, provider_partnership, params:) + end + + def create + @provider_partnership_form = ProviderPartnershipForm.new(current_user, @provider_partnership, params: partnership_params) + + if @provider_partnership_form.stash + redirect_to check_publish_provider_recruitment_cycle_accredited_partnerships_path(@provider.provider_code, recruitment_cycle.year) + else + render :new + end + end + + def update + @provider_partnership = provider.accredited_partnerships.find_by(accredited_provider_id: partner.id) + @provider_partnership_form = ProviderPartnershipForm.new(current_user, @provider_partnership, params: partnership_params) + + if @provider_partnership_form.save! + flash[:success] = t('.edit.updated') + redirect_to publish_provider_recruitment_cycle_accredited_partnerships_path(@provider.provider_code, recruitment_cycle.year) + else + render :edit + end + end + + def delete + @provider_partnership = provider.accredited_partnerships.find_by(accredited_provider: partner) + cannot_delete + end + + def destroy + @partnership = provider.accredited_partnerships.find_by(accredited_provider_id: partner.id) + + if @partnership.destroy + flash[:success] = t('.delete.updated') + redirect_to publish_provider_recruitment_cycle_accredited_partnerships_path(@provider.provider_code, recruitment_cycle.year) + else + render :delete + end + end + + private + + def cannot_delete + @cannot_delete ||= provider.courses.exists?(accredited_provider_code: params[:accredited_provider_code]) + end + + def provider + @provider = recruitment_cycle.providers.find_by(provider_code: params[:provider_code]) + end + + def partner + recruitment_cycle.providers.find_by(provider_code: params[:accredited_provider_code]) + end + + def partnership_params + params.require(:provider_partnership_form).permit(:accredited_provider_id, :description) + end + end + end +end diff --git a/app/controllers/publish/providers/accredited_provider_search_controller.rb b/app/controllers/publish/providers/accredited_provider_search_controller.rb index fb23870f1d..816b875d16 100644 --- a/app/controllers/publish/providers/accredited_provider_search_controller.rb +++ b/app/controllers/publish/providers/accredited_provider_search_controller.rb @@ -11,11 +11,19 @@ def new def create if accredited_provider_id.present? - redirect_to new_publish_provider_recruitment_cycle_accredited_provider_path( - provider_code: provider.provider_code, - recruitment_cycle_year: provider.recruitment_cycle_year, - accredited_provider_id: - ) + if Settings.features.provider_partnerships + redirect_to new_publish_provider_recruitment_cycle_accredited_partnership_path( + provider_code: provider.provider_code, + recruitment_cycle_year: provider.recruitment_cycle_year, + accredited_provider_id: + ) + else + redirect_to new_publish_provider_recruitment_cycle_accredited_provider_path( + provider_code: provider.provider_code, + recruitment_cycle_year: provider.recruitment_cycle_year, + accredited_provider_id: + ) + end else @accredited_provider_search_form = AccreditedProviderSearchForm.new(query:) @@ -34,11 +42,19 @@ def update @accredited_provider_select_form = AccreditedProviderSelectForm.new(provider_id: accredited_provider_select_params[:provider_id]) if @accredited_provider_select_form.valid? - redirect_to new_publish_provider_recruitment_cycle_accredited_provider_path( - provider_code: provider.provider_code, - recruitment_cycle_year: provider.recruitment_cycle_year, - accredited_provider_id: accredited_provider_select_params[:provider_id] - ) + if Settings.features.provider_partnerships + redirect_to new_publish_provider_recruitment_cycle_accredited_partnership_path( + provider_code: provider.provider_code, + recruitment_cycle_year: provider.recruitment_cycle_year, + accredited_provider_id: accredited_provider_select_params[:provider_id] + ) + else + redirect_to new_publish_provider_recruitment_cycle_accredited_provider_path( + provider_code: provider.provider_code, + recruitment_cycle_year: provider.recruitment_cycle_year, + accredited_provider_id: accredited_provider_select_params[:provider_id] + ) + end else @accredited_provider_search = ::AccreditedProviders::SearchService.call(query:, recruitment_cycle_year: params[:recruitment_cycle_year]) render :results diff --git a/app/controllers/publish/providers/v2/training_providers/course_exports_controller.rb b/app/controllers/publish/providers/v2/training_providers/course_exports_controller.rb new file mode 100644 index 0000000000..af9fc14a12 --- /dev/null +++ b/app/controllers/publish/providers/v2/training_providers/course_exports_controller.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Publish + module Providers + module V2 + module TrainingProviders + class CourseExportsController < ApplicationController + def index + authorize(provider, :can_list_training_providers?) + + respond_to do |format| + format.csv do + send_data(data_export.data, filename: data_export.filename, disposition: :attachment) + end + end + end + + private + + def courses + @courses ||= provider.current_accredited_courses + end + + def data_export + @data_export ||= Exports::AccreditedCourseList.new(courses:) + end + end + end + end + end +end diff --git a/app/controllers/publish/providers/v2/training_providers/courses_controller.rb b/app/controllers/publish/providers/v2/training_providers/courses_controller.rb new file mode 100644 index 0000000000..5d454641ea --- /dev/null +++ b/app/controllers/publish/providers/v2/training_providers/courses_controller.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Publish + module Providers + module V2 + module TrainingProviders + class CoursesController < ApplicationController + def index + authorize(provider, :index?) + + @courses = fetch_courses + end + + private + + def training_provider + @training_provider ||= provider.training_partners.find_by(provider_code: params[:training_provider_code]) + end + + def fetch_courses + training_provider + .courses + .includes(:enrichments, :site_statuses, provider: [:recruitment_cycle]) + .where(accredited_provider_code: provider.provider_code) + .order(:name) + .map(&:decorate) + end + end + end + end + end +end diff --git a/app/controllers/publish/providers/v2/training_providers_controller.rb b/app/controllers/publish/providers/v2/training_providers_controller.rb new file mode 100644 index 0000000000..e60b342385 --- /dev/null +++ b/app/controllers/publish/providers/v2/training_providers_controller.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Publish + module Providers + module V2 + class TrainingProvidersController < ApplicationController + def index + authorize(provider, :can_list_training_providers?) + + @training_providers = provider.training_partners.include_accredited_courses_counts(provider.provider_code).order(:provider_name) + @course_counts = @training_providers.to_h { |p| [p.provider_code, p.accredited_courses_count] } + end + end + end + end +end diff --git a/app/controllers/support/providers/accredited_partners/checks_controller.rb b/app/controllers/support/providers/accredited_partners/checks_controller.rb new file mode 100644 index 0000000000..1c2531fba1 --- /dev/null +++ b/app/controllers/support/providers/accredited_partners/checks_controller.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +module Support + module Providers + module AccreditedPartners + class ChecksController < ApplicationController + include ClearStashable + + def show + accredited_provider_form + end + + def update + @partnership = provider.accredited_partnerships.build(accredited_provider_id: accredited_provider_form.accredited_provider_id, + description: accredited_provider_form.description) + if @partnership.save + notify_accredited_provider_users + + redirect_to support_recruitment_cycle_provider_accredited_partners_path( + recruitment_cycle.year, provider.id + ), flash: { success: 'Accredited partner added' } + else + render :show + end + end + + private + + def accredited_provider_form + @accredited_provider_form ||= ProviderPartnershipForm.new(current_user, new_partnership) + end + + def provider + @provider ||= recruitment_cycle.providers.find(params[:provider_id]) + end + + def new_partnership + @new_partnership = provider.accredited_partnerships.build + end + + def partner + Provider.find(accredited_provider_form.accredited_provider_id) + end + + def notify_accredited_provider_users + @partnership.accredited_provider.users.each do |user| + ::Users::OrganisationMailer.added_as_an_organisation_to_training_partner( + recipient: user, + provider: provider, + accredited_provider: @partnership.accredited_provider + ).deliver_later + end + end + end + end + end +end diff --git a/app/controllers/support/providers/accredited_partners_controller.rb b/app/controllers/support/providers/accredited_partners_controller.rb new file mode 100644 index 0000000000..09b63a8236 --- /dev/null +++ b/app/controllers/support/providers/accredited_partners_controller.rb @@ -0,0 +1,114 @@ +# frozen_string_literal: true + +module Support + module Providers + class AccreditedPartnersController < ApplicationController + include ClearStashable + + helper_method :accredited_provider_id + + before_action :reset_accredited_provider_form, only: %i[index] + + def index + @pagy, @accredited_partnerships = pagy(provider.accredited_partnerships) + render layout: 'provider_record' + end + + def new + accredited_provider_form + end + + def edit + provider + provider_partnership = provider.accredited_partnerships.find_by(accredited_provider: partner) + params = { accredited_provider_id: partner.id, description: provider_partnership.description } + @accredited_provider_form = ::ProviderPartnershipForm.new(current_user, provider_partnership, params:) + end + + def create + @accredited_provider_form = ::ProviderPartnershipForm.new(current_user, provider, params: accredited_provider_params) + if @accredited_provider_form.stash + redirect_to check_support_recruitment_cycle_provider_accredited_partners_path(accredited_provider_id: partnership_params[:accredited_provider_id]) + else + render :new + end + end + + def update + provider_partnership = provider.accredited_partnerships.find_by(accredited_provider: partner) + @accredited_provider_form = ::ProviderPartnershipForm.new(current_user, provider_partnership, params: accredited_provider_params) + + if @accredited_provider_form.save! + redirect_to support_recruitment_cycle_provider_accredited_partners_path( + recruitment_cycle_year: @recruitment_cycle.year, + provider_id: @provider.id + ) + + flash[:success] = t('support.providers.accredited_providers.edit.updated') + else + accredited_provider + render(:edit) + end + end + + def delete + cannot_delete + @accredited_provider = partner + end + + def destroy + return if cannot_delete + + provider.accredited_partnerships.find_by(accredited_provider_id: partner.id).destroy + + flash[:success] = t('support.providers.accredited_providers.delete.updated') + + redirect_to support_recruitment_cycle_provider_accredited_partners_path( + recruitment_cycle_year: @recruitment_cycle.year, + provider_id: @provider.id + ) + end + + private + + def cannot_delete + @cannot_delete ||= provider.courses.exists?(accredited_provider_code: partner.provider_code) + end + + def accrediting_provider_enrichments + provider.accrediting_provider_enrichments.reject { |enrichment| enrichment.UcasProviderCode == params['accredited_provider_code'] } + end + + def provider + @provider ||= recruitment_cycle.providers.find(params[:provider_id]) + end + + def accredited_provider_id + params[:accredited_provider_id] || @accredited_provider_form.accredited_provider_id + end + + def accredited_provider_form + @accredited_provider_form ||= ::ProviderPartnershipForm.new(current_user, partnership) + end + + def accredited_provider_params + params.require(:provider_partnership_form) + .except(:goto_confirmation) + .permit(::ProviderPartnershipForm::FIELDS) + end + + def partner + recruitment_cycle.providers.find_by(provider_code: params[:accredited_provider_code]) + end + + def partnership + @partnership = provider.accredited_partnerships.find_or_initialize_by(accredited_provider: partner) + @partnership.description ||= params[:description] + end + + def partnership_params + params.require(:provider_partnership_form).permit(:accredited_provider_id, :description) + end + end + end +end diff --git a/app/controllers/support/providers/accredited_provider_search_controller.rb b/app/controllers/support/providers/accredited_provider_search_controller.rb index 8d7465e257..04707bfd24 100644 --- a/app/controllers/support/providers/accredited_provider_search_controller.rb +++ b/app/controllers/support/providers/accredited_provider_search_controller.rb @@ -30,7 +30,11 @@ def update @accredited_provider_select_form = AccreditedProviderSelectForm.new(provider_id: accredited_provider_select_params[:provider_id]) if @accredited_provider_select_form.valid? - redirect_to new_support_recruitment_cycle_provider_accredited_provider_path(accredited_provider_id: accredited_provider_select_params[:provider_id]) + if Settings.features.provider_partnerships + redirect_to new_support_recruitment_cycle_provider_accredited_partner_path(accredited_provider_id: accredited_provider_select_params[:provider_id]) + else + redirect_to new_support_recruitment_cycle_provider_accredited_provider_path(accredited_provider_id: accredited_provider_select_params[:provider_id]) + end else @accredited_provider_search = ::AccreditedProviders::SearchService.call(query:, recruitment_cycle_year: params[:recruitment_cycle_year]) render :results @@ -76,7 +80,11 @@ def search_result_title_component end def redirect_to_next_step - redirect_to new_support_recruitment_cycle_provider_accredited_provider_path(accredited_provider_id:) + if Settings.features.provider_partnerships + redirect_to new_support_recruitment_cycle_provider_accredited_partner_path(accredited_provider_id:) + else + redirect_to new_support_recruitment_cycle_provider_accredited_provider_path(accredited_provider_id:) + end end end end diff --git a/app/forms/provider_partnership_form.rb b/app/forms/provider_partnership_form.rb new file mode 100644 index 0000000000..6ffcd61d90 --- /dev/null +++ b/app/forms/provider_partnership_form.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +class ProviderPartnershipForm < Form + delegate :provider_name, to: :accredited_provider + + FIELDS = %i[ + description + accredited_provider_id + ].freeze + + attr_accessor(*FIELDS) + + validates :description, presence: true, words_count: { maximum: 100, message: :too_long } + + alias compute_fields new_attributes + + def accredited_provider + @accredited_provider ||= Provider.find(accredited_provider_id) + end + + private + + def assign_attributes_to_model + if model.persisted? + model.description = description + else + model.accredited_partnerships.build(accredited_provider_id: accredited_provider_id, description: description) + end + end + + def after_save + accredited_provider.users.each do |user| + ::Users::OrganisationMailer.added_as_an_organisation_to_training_partner( + recipient: user, + provider: model, + accredited_provider: + ).deliver_later + end + end +end diff --git a/app/helpers/goto_confirmation_helper.rb b/app/helpers/goto_confirmation_helper.rb index 2be3248c6e..9668ab8eb4 100644 --- a/app/helpers/goto_confirmation_helper.rb +++ b/app/helpers/goto_confirmation_helper.rb @@ -19,7 +19,17 @@ def back_link_for_onboarding_path(param_form_key:, params:, recruitment_cycle_ye end end - def back_link_for_adding_accrediting_provider_path(param_form_key:, params:, recruitment_cycle_year:, provider:) + def back_link_for_adding_accredited_partner_path(param_form_key:, params:, recruitment_cycle_year:, provider:) + with_partnerships = if goto_confirmation?(param_form_key:, params:) + check_support_recruitment_cycle_provider_accredited_partners_path(recruitment_cycle_year, provider) + elsif param_form_key == :support_accredited_provider_form + search_support_recruitment_cycle_provider_accredited_partners_path + else + support_recruitment_cycle_provider_accredited_partners_path(recruitment_cycle_year, provider) + end + + return with_partnerships if Settings.features.provider_partnerships + if goto_confirmation?(param_form_key:, params:) check_support_recruitment_cycle_provider_accredited_providers_path(recruitment_cycle_year, provider) elsif param_form_key == :support_accredited_provider_form @@ -29,7 +39,17 @@ def back_link_for_adding_accrediting_provider_path(param_form_key:, params:, rec end end - def publish_back_link_for_adding_accrediting_provider_path(param_form_key:, params:, recruitment_cycle_year:, provider:) + def publish_back_link_for_adding_provider_partnership_path(param_form_key:, params:, recruitment_cycle_year:, provider:) + with_partnerships = if goto_confirmation?(param_form_key:, params:) + check_publish_provider_recruitment_cycle_accredited_partnerships_path(provider.provider_code, recruitment_cycle_year) + elsif param_form_key == :publish_accredited_provider_form + search_publish_provider_recruitment_cycle_accredited_partnerships_path(provider.provider_code, recruitment_cycle_year) + else + publish_provider_recruitment_cycle_accredited_partnerships_path(provider.provider_code, recruitment_cycle_year) + end + + return with_partnerships if Settings.features.provider_partnerships + if goto_confirmation?(param_form_key:, params:) check_publish_provider_recruitment_cycle_accredited_providers_path(provider.provider_code, recruitment_cycle_year) elsif param_form_key == :publish_accredited_provider_form diff --git a/app/helpers/navigation_bar_helper.rb b/app/helpers/navigation_bar_helper.rb index 5ce3131249..950e8ae964 100644 --- a/app/helpers/navigation_bar_helper.rb +++ b/app/helpers/navigation_bar_helper.rb @@ -13,9 +13,22 @@ def navigation_items(provider) { name: t('navigation_bar.schools'), url: publish_provider_recruitment_cycle_schools_path(provider.provider_code, provider.recruitment_cycle_year) }, { name: t('navigation_bar.study_sites'), url: publish_provider_recruitment_cycle_study_sites_path(provider.provider_code, provider.recruitment_cycle_year) }, { name: t('navigation_bar.users'), url: publish_provider_users_path(provider_code: provider.provider_code), additional_url: request_access_publish_provider_path(provider.provider_code) }, - *([name: t('navigation_bar.training_partners'), url: publish_provider_recruitment_cycle_training_providers_path(provider.provider_code, provider.recruitment_cycle_year)] if provider.accredited_provider?), - *([name: t('navigation_bar.accredited_provider'), url: publish_provider_recruitment_cycle_accredited_providers_path(provider.provider_code, provider.recruitment_cycle_year)] unless provider.accredited_provider?), + partnership_links(provider), { name: t('navigation_bar.organisation_details'), url: details_publish_provider_recruitment_cycle_path(provider.provider_code, provider.recruitment_cycle_year) } ] end + + def partnership_links(provider) + if Settings.features.provider_partnerships + if provider.accredited_provider? + { name: t('navigation_bar.training_partners'), url: publish_provider_recruitment_cycle_training_providers_path(provider.provider_code, provider.recruitment_cycle_year) } + else + { name: t('navigation_bar.accredited_partnerships'), url: publish_provider_recruitment_cycle_accredited_partnerships_path(provider.provider_code, provider.recruitment_cycle_year) } + end + elsif provider.accredited_provider? + { name: t('navigation_bar.training_partners'), url: publish_provider_recruitment_cycle_training_providers_path(provider.provider_code, provider.recruitment_cycle_year) } + else + { name: t('navigation_bar.accredited_provider'), url: publish_provider_recruitment_cycle_accredited_providers_path(provider.provider_code, provider.recruitment_cycle_year) } + end + end end diff --git a/app/helpers/publish/back_link_helper.rb b/app/helpers/publish/back_link_helper.rb index 3c8c23303a..bbfe6238fb 100644 --- a/app/helpers/publish/back_link_helper.rb +++ b/app/helpers/publish/back_link_helper.rb @@ -44,6 +44,10 @@ def study_mode_path(course) end end + def accredited_provider_search_path(param_form_key:, params:, provider:, recruitment_cycle_year:) + publish_back_link_for_adding_provider_partnership_path(param_form_key:, params:, recruitment_cycle_year:, provider:) + end + private def previously_tda_course? diff --git a/app/helpers/view_helper.rb b/app/helpers/view_helper.rb index 879c257d04..f395c8202d 100644 --- a/app/helpers/view_helper.rb +++ b/app/helpers/view_helper.rb @@ -47,6 +47,7 @@ def title_with_error_prefix(title, error) def enrichment_error_url(provider_code:, course:, field:, message: nil) base = "/publish/organisations/#{provider_code}/#{course.recruitment_cycle_year}/courses/#{course.course_code}" provider_base = "/publish/organisations/#{provider_code}/#{course.recruitment_cycle_year}" + accrediting_provider = Settings.features.provider_partnerships ? ratifying_provider_publish_provider_recruitment_cycle_course_path(course.provider_code, course.recruitment_cycle_year, course.course_code) : accredited_provider_publish_provider_recruitment_cycle_course_path(course.provider_code, course.recruitment_cycle_year, course.course_code) if field.to_sym == :base base_errors_hash(provider_code, course)[message] @@ -62,7 +63,7 @@ def enrichment_error_url(provider_code:, course:, field:, message: nil) age_range_in_years: "#{base}/age-range?display_errors=true", sites: "#{base}/schools?display_errors=true", study_sites: (course.provider&.study_sites&.none? ? "#{provider_base}/study-sites" : "#{base}/study-sites").to_s, - accrediting_provider: accredited_provider_publish_provider_recruitment_cycle_course_path(course.provider_code, course.recruitment_cycle_year, course.course_code), + accrediting_provider:, applications_open_from: "#{base}/applications-open", a_level_subject_requirements: publish_provider_recruitment_cycle_course_a_levels_what_a_level_is_required_path( course.provider_code, @@ -165,11 +166,19 @@ def x_provider_url def x_accrediting_provider_url if preview?(params) - accredited_by_publish_provider_recruitment_cycle_course_path( - course.provider_code, - course.recruitment_cycle_year, - course.course_code - ) + if Settings.features.provider_partnerships + ratified_by_publish_provider_recruitment_cycle_course_path( + course.provider_code, + course.recruitment_cycle_year, + course.course_code + ) + else + accredited_by_publish_provider_recruitment_cycle_course_path( + course.provider_code, + course.recruitment_cycle_year, + course.course_code + ) + end else find_accrediting_provider_path(course.provider_code, course.course_code) end diff --git a/app/lib/constraints/partnership_feature.rb b/app/lib/constraints/partnership_feature.rb new file mode 100644 index 0000000000..98dbef6cba --- /dev/null +++ b/app/lib/constraints/partnership_feature.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Constraints + class PartnershipFeature + def initialize(setting) + @setting = setting + end + + def matches?(_request) + if @setting == :on + Settings.features.provider_partnerships + else + !Settings.features.provider_partnerships + end + end + end +end diff --git a/app/models/concerns/publish/course_basic_detail_concern.rb b/app/models/concerns/publish/course_basic_detail_concern.rb index 4c3899ef33..7bcf350848 100644 --- a/app/models/concerns/publish/course_basic_detail_concern.rb +++ b/app/models/concerns/publish/course_basic_detail_concern.rb @@ -207,8 +207,12 @@ def course_creation_path_for(page) end when :applications_open new_publish_provider_recruitment_cycle_courses_applications_open_path(path_params) - when :accredited_provider - new_publish_provider_recruitment_cycle_courses_accredited_provider_path(path_params) + when :accredited_provider, :ratifying_provider + if Settings.features.provider_partnerships + new_publish_provider_recruitment_cycle_courses_ratifying_provider_path(path_params) + else + new_publish_provider_recruitment_cycle_courses_accredited_provider_path(path_params) + end when :can_sponsor_student_visa new_publish_provider_recruitment_cycle_courses_student_visa_sponsorship_path(path_params) when :can_sponsor_skilled_worker_visa diff --git a/app/models/course.rb b/app/models/course.rb index f91fba6a84..b34788d2d2 100644 --- a/app/models/course.rb +++ b/app/models/course.rb @@ -429,6 +429,13 @@ def generate_name Courses::GenerateCourseNameService.call(course: self) end + def ratifying_provider_description + return nil unless accrediting_provider + + subquery = RecruitmentCycle.current.providers.where(provider_code: accrediting_provider.provider_code).select(:id) + provider.accredited_partnerships.find_by(accredited_provider_id: subquery)&.description + end + def accrediting_provider_description return if accrediting_provider.blank? return if provider.accrediting_provider_enrichments.blank? diff --git a/app/models/provider_partnership.rb b/app/models/provider_partnership.rb index 858057992c..363f63954d 100644 --- a/app/models/provider_partnership.rb +++ b/app/models/provider_partnership.rb @@ -7,6 +7,7 @@ class ProviderPartnership < ApplicationRecord validates :accredited_provider, uniqueness: { scope: %i[training_provider_id] } validate :accredited_provider_must_be_accredited validate :training_provider_must_not_be_accredited + validates :description, presence: true, words_count: { maximum: 100, message: :too_long } def accredited_provider_must_be_accredited return if accredited_provider.blank? diff --git a/app/serializers/api/public/v1/serializable_course.rb b/app/serializers/api/public/v1/serializable_course.rb index b844ac4b56..b829421aa2 100644 --- a/app/serializers/api/public/v1/serializable_course.rb +++ b/app/serializers/api/public/v1/serializable_course.rb @@ -54,7 +54,11 @@ def enrichment_attribute(name, enrichment_name = name) :degree_type attribute :about_accredited_body do - @object.accrediting_provider_description + if Settings.features.provider_partnerships + @object.ratifying_provider_description + else + @object.accrediting_provider_description + end end attribute :accredited_body_code do diff --git a/app/services/stores/user_store.rb b/app/services/stores/user_store.rb index b1d9696527..32021b0d80 100644 --- a/app/services/stores/user_store.rb +++ b/app/services/stores/user_store.rb @@ -7,6 +7,7 @@ class UserStore < BaseStore provider provider_contact accredited_provider + provider_partnership ].freeze def store_keys diff --git a/app/views/layouts/provider_record.html.erb b/app/views/layouts/provider_record.html.erb index 9da8b899d9..22ba9a591e 100644 --- a/app/views/layouts/provider_record.html.erb +++ b/app/views/layouts/provider_record.html.erb @@ -10,13 +10,20 @@
<%= Provider.human_attribute_name(@provider.provider_type) %>

<%= @provider.name_and_code %>

- + <% accredited_tab = [{ url: "", name: "" }] %> + <% unless @provider.accredited_provider? %> + <% if Settings.features.provider_partnerships %> + <% accredited_tab = [{ name: "Accredited partnerships", url: support_recruitment_cycle_provider_accredited_partners_path(@provider.recruitment_cycle_year, @provider) }] %> + <% else %> + <% accredited_tab = [{ name: "Accredited providers", url: support_recruitment_cycle_provider_accredited_providers_path(@provider.recruitment_cycle_year, @provider) }] %> + <% end %> + <% end %> <%= render TabNavigation.new(items: [ { name: "Details", url: support_recruitment_cycle_provider_path(@provider.recruitment_cycle_year, @provider) }, { name: "Users", url: support_recruitment_cycle_provider_users_path(@provider.recruitment_cycle_year, @provider) }, { name: "Courses", url: support_recruitment_cycle_provider_courses_path(@provider.recruitment_cycle_year, @provider) }, { name: "Schools", url: support_recruitment_cycle_provider_schools_path(@provider.recruitment_cycle_year, @provider) }, - *([{ name: "Accredited providers", url: support_recruitment_cycle_provider_accredited_providers_path(@provider.recruitment_cycle_year, @provider) }] unless @provider.accredited_provider?) + *accredited_tab ]) %> <%= yield %> diff --git a/app/views/publish/courses/_basic_details_tab.html.erb b/app/views/publish/courses/_basic_details_tab.html.erb index 18900b33b3..27d250d7e9 100644 --- a/app/views/publish/courses/_basic_details_tab.html.erb +++ b/app/views/publish/courses/_basic_details_tab.html.erb @@ -152,22 +152,41 @@ end end + if Settings.features.provider_partnerships + heading = "Ratifying provider" + partners = @provider.accredited_partners + add_provider_text = "Add at least one accredited partner" + add_provider_link = publish_provider_recruitment_cycle_accredited_partnerships_path(@course.provider_code, @course.recruitment_cycle_year) + select_partner_text = "Select an accredited partner" + select_partner_link = ratifying_provider_publish_provider_recruitment_cycle_course_path(@course.provider_code, @course.recruitment_cycle_year, @course.course_code) + change_partner_link = ratifying_provider_publish_provider_recruitment_cycle_course_path(@provider.provider_code, course.recruitment_cycle_year, course.course_code) + # select_partner_link = ratifying_provider_publish_provider_recruitment_cycle_course_path(@course.provider_code, @course.recruitment_cycle_year, @course.course_code) + else + heading = "Accredited provider" + partners = @provider.accredited_providers + add_provider_text = "Add at least one accredited provider" + add_provider_link = publish_provider_recruitment_cycle_accredited_providers_path(@course.provider_code, @course.recruitment_cycle_year) + select_partner_text = "Select an accredited provider" + select_partner_link = accredited_provider_publish_provider_recruitment_cycle_course_path(@course.provider_code, @course.recruitment_cycle_year, @course.course_code) + change_partner_link = accredited_provider_publish_provider_recruitment_cycle_course_path(@provider.provider_code, course.recruitment_cycle_year, course.course_code) + end + unless @provider.accredited_provider? summary_list.with_row(html_attributes: { data: { qa: "course__accredited_provider" } }) do |row| - row.with_key { "Accredited provider" } + row.with_key { heading } row.with_value { course.accrediting_provider&.provider_name } if course.is_published? || course.is_withdrawn? row.with_action elsif !course.accrediting_provider.nil? - row.with_action(href: accredited_provider_publish_provider_recruitment_cycle_course_path(@provider.provider_code, course.recruitment_cycle_year, course.course_code), + row.with_action(href: change_partner_link, visually_hidden_text: "accredited provider") - elsif @provider.accredited_providers.any? + elsif partners.any? row.with_value do - "
#{govuk_link_to('Select an accredited provider', accredited_provider_publish_provider_recruitment_cycle_course_path(@course.provider_code, @course.recruitment_cycle_year, @course.course_code))}
".html_safe + "
#{govuk_link_to(select_partner_text, select_partner_link)}
".html_safe end else row.with_value do - "
#{govuk_link_to('Add at least one accredited provider', publish_provider_recruitment_cycle_accredited_providers_path(@course.provider_code, @course.recruitment_cycle_year))}
".html_safe + "
#{govuk_link_to(add_provider_text, add_provider_link)}
".html_safe end end end diff --git a/app/views/publish/courses/confirmation.html.erb b/app/views/publish/courses/confirmation.html.erb index 54c8f5ee99..2a7c313fd6 100644 --- a/app/views/publish/courses/confirmation.html.erb +++ b/app/views/publish/courses/confirmation.html.erb @@ -153,12 +153,12 @@ <% unless @provider.accredited_provider? || course.is_further_education? %> <% summary_list.with_row(html_attributes: { data: { qa: "course__accredited_provider" } }) do |row| %> - <% row.with_key { "Accredited provider" } %> + <% row.with_key { "Ratifying provider" } %> <% row.with_value { course.accrediting_provider.provider_name } %> <% if @provider.accredited_bodies.length > 1 %> <% row.with_action( href: new_publish_provider_recruitment_cycle_courses_accredited_provider_path(course.provider.provider_code, course.recruitment_cycle.year, params.to_unsafe_h.merge(goto_confirmation: true)), - visually_hidden_text: "accredited provider" + visually_hidden_text: "ratifying provider" ) %> <% else %> <% row.with_action %> diff --git a/app/views/publish/courses/index.html.erb b/app/views/publish/courses/index.html.erb index 978e2db780..0e768d564e 100644 --- a/app/views/publish/courses/index.html.erb +++ b/app/views/publish/courses/index.html.erb @@ -3,7 +3,11 @@

Courses

+<% if Settings.features.provider_partnerships %> +<%= render AddCourseButtonPartnerships.new(provider: @provider) %> +<% else %> <%= render AddCourseButton.new(provider: @provider) %> +<% end %> <% if @self_accredited_courses %>
@@ -14,7 +18,7 @@ <% @courses_by_accrediting_provider.each do |accrediting_provider, courses| %>

- Accredited provider + Ratifying provider <%= accrediting_provider %>

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..d2377b27ff --- /dev/null +++ b/app/views/publish/courses/ratifying_provider/new.html.erb @@ -0,0 +1,41 @@ +<% content_for :page_title, title_with_error_prefix("Ratifying 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" %> + +<% url = Settings.features.provider_partnerships ? continue_publish_provider_recruitment_cycle_courses_ratifying_provider_path(@provider.provider_code, @provider.recruitment_cycle_year) : continue_publish_provider_recruitment_cycle_courses_accredited_provider_path(@provider.provider_code, @provider.recruitment_cycle_year) %> +
+
+ <%= form_with url:, 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")) %> + Ratifying 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/app/views/publish/providers/accredited_partnerships/_can_remove.html.erb b/app/views/publish/providers/accredited_partnerships/_can_remove.html.erb new file mode 100644 index 0000000000..6236954981 --- /dev/null +++ b/app/views/publish/providers/accredited_partnerships/_can_remove.html.erb @@ -0,0 +1,23 @@ +<%= content_for :page_title, t("publish.providers.provider_partnerships.delete.title") %> + +<% content_for :before_content do %> + <%= govuk_back_link_to(publish_provider_recruitment_cycle_accredited_partnerships_path) %> +<% end %> + +
+
+

+ <%= @provider_partnership.accredited_provider.provider_name %> + <%= t("publish.providers.provider_partnerships.delete.title") %> +

+ + <%= govuk_button_to "Remove accredited partnership", + delete_publish_provider_recruitment_cycle_accredited_partnership_path, + method: :delete, + class: "govuk-button--warning" %> + +

+ <%= govuk_link_to(t("cancel"), publish_provider_recruitment_cycle_accredited_partnerships_path) %> +

+
+
diff --git a/app/views/publish/providers/accredited_partnerships/_cannot_remove.html.erb b/app/views/publish/providers/accredited_partnerships/_cannot_remove.html.erb new file mode 100644 index 0000000000..701333e394 --- /dev/null +++ b/app/views/publish/providers/accredited_partnerships/_cannot_remove.html.erb @@ -0,0 +1,29 @@ +<% content_for :page_title, "You cannot remove this accredited provider" %> + +<% content_for :before_content do %> + <%= govuk_back_link_to(publish_provider_recruitment_cycle_accredited_providers_path) %> +<% end %> + +
+
+

+ <%= @provider_partnership.accredited_provider.provider_name %> + You cannot remove this accredited provider +

+ +

+ <%= @provider_partnership.accredited_provider.provider_name %> is an + accredited provider for courses run by <%= @provider.provider_name %>. At least one of these courses is + currently published on Find. +

+ +

+ If you need to change an accredited provider for a course which is published, please contact us at + <%= bat_contact_mail_to %>. +

+ +

+ <%= govuk_link_to(t("cancel"), publish_provider_recruitment_cycle_accredited_partnerships_path) %> +

+
+
diff --git a/app/views/publish/providers/accredited_partnerships/_hint.html.erb b/app/views/publish/providers/accredited_partnerships/_hint.html.erb new file mode 100644 index 0000000000..d8c0c849fc --- /dev/null +++ b/app/views/publish/providers/accredited_partnerships/_hint.html.erb @@ -0,0 +1,2 @@ +

<%= hint %>

+<%= render partial: "publish/courses/markdown_formatting" %> diff --git a/app/views/publish/providers/accredited_partnerships/checks/show.html.erb b/app/views/publish/providers/accredited_partnerships/checks/show.html.erb new file mode 100644 index 0000000000..6bd5c266a5 --- /dev/null +++ b/app/views/publish/providers/accredited_partnerships/checks/show.html.erb @@ -0,0 +1,42 @@ +<%= render PageTitle.new( + title: "Check your answers - #{t('.title')}" +) %> + +<% content_for :before_content do %> + <%= govuk_back_link_to(new_publish_provider_recruitment_cycle_accredited_partnership_path(provider_code: @provider.provider_code, + recruitment_cycle_year: @provider.recruitment_cycle_year)) %> +<% end %> + +
+
+ + <%= form_with(url: check_publish_provider_recruitment_cycle_accredited_partnerships_path, method: :put, local: true) do |f| %> +

+ <%= t(".caption") %> + Check your answers +

+ + <%= render GovukComponent::SummaryListComponent.new do |component| + component.with_row do |row| + row.with_key { "Accredited provider" } + row.with_value { @provider_partnership_form.provider_name } + row.with_action(text: "Change", href: search_publish_provider_accredited_providers_recruitment_cycles_path(goto_confirmation: true), visually_hidden_text: "accredited provider name") + end + + component.with_row do |row| + row.with_key { "About the accredited provider" } + row.with_value { markdown @provider_partnership_form.description } + row.with_action(text: "Change", href: new_publish_provider_recruitment_cycle_accredited_partnership_path(goto_confirmation: true), visually_hidden_text: "accredited provider description") + end + end %> + + <%= govuk_warning_text(text: "All users at #{@provider_partnership_form.provider_name} will be sent an email to let them know they’ve been added.") %> + + <%= f.govuk_submit(t(".add")) %> + <% end %> + +

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

+
+
diff --git a/app/views/publish/providers/accredited_partnerships/delete.html.erb b/app/views/publish/providers/accredited_partnerships/delete.html.erb new file mode 100644 index 0000000000..a6d881ade7 --- /dev/null +++ b/app/views/publish/providers/accredited_partnerships/delete.html.erb @@ -0,0 +1 @@ +<%= render partial: @cannot_delete ? "cannot_remove" : "can_remove" %> diff --git a/app/views/publish/providers/accredited_partnerships/edit.html.erb b/app/views/publish/providers/accredited_partnerships/edit.html.erb new file mode 100644 index 0000000000..3f00b5a723 --- /dev/null +++ b/app/views/publish/providers/accredited_partnerships/edit.html.erb @@ -0,0 +1,36 @@ +<% content_for :page_title, title_with_error_prefix("About the accredited provider - #{@provider_partnership_form.accredited_provider.provider_name}", @provider_partnership_form.errors.present?) %> + + <%= form_with( + model: @provider_partnership_form, + url: publish_provider_recruitment_cycle_accredited_partnership_path, + method: :put + ) do |f| %> + + <%= f.govuk_error_summary %> + +
+
+ + <% content_for :before_content do %> + <%= govuk_back_link_to(publish_provider_recruitment_cycle_accredited_partnerships_path) %> + <% end %> + + <%= f.govuk_text_area( + :description, + label: { text: t(".title"), size: "l", tag: "h1" }, + hint: -> { render "hint", hint: t(".hint") }, + caption: { text: @provider_partnership_form.accredited_provider.provider_name, size: "l" }, + max_words: 100, + rows: 10 + ) %> + + <%= f.hidden_field :accredited_provider_id, value: @provider_partnership_form.accredited_provider_id %> + + <%= f.govuk_submit "Update description" %> + +

+ <%= govuk_link_to(t("cancel"), publish_provider_recruitment_cycle_accredited_partnerships_path) %> +

+
+
+<% end %> diff --git a/app/views/publish/providers/accredited_partnerships/index.html.erb b/app/views/publish/providers/accredited_partnerships/index.html.erb new file mode 100644 index 0000000000..9104f051ed --- /dev/null +++ b/app/views/publish/providers/accredited_partnerships/index.html.erb @@ -0,0 +1,26 @@ +<% content_for :page_title, title_with_error_prefix("Accredited providers", nil) %> + +
+
+

+ Accredited partnerships +

+ + <%= govuk_button_link_to("Add accredited partnership", search_publish_provider_accredited_providers_recruitment_cycles_path( + provider_code: @provider.provider_code, + recruitment_cycle_year: @provider.recruitment_cycle_year + )) %> +
+
+ +
+
+ <% if @provider.accredited_partnerships.none? %> +

There are no accredited providers for <%= @provider.provider_name %>.

+ <% else %> + <% @provider.accredited_partnerships.each do |partnership| %> + <%= render AccreditedProviderComponent.new(provider_name: partnership.accredited_provider.provider_name, remove_path: delete_publish_provider_recruitment_cycle_accredited_partnership_path(accredited_provider_code: partnership.accredited_provider.provider_code), about_accredited_provider: partnership.description, change_about_accredited_provider_path: edit_publish_provider_recruitment_cycle_accredited_partnership_path(accredited_provider_code: partnership.accredited_provider.provider_code)) %> + <% end %> + <% end %> +
+
diff --git a/app/views/publish/providers/accredited_partnerships/new.html.erb b/app/views/publish/providers/accredited_partnerships/new.html.erb new file mode 100644 index 0000000000..50fb45acd7 --- /dev/null +++ b/app/views/publish/providers/accredited_partnerships/new.html.erb @@ -0,0 +1,36 @@ +<% content_for :page_title, title_with_error_prefix("About the accredited provider - Add accredited provider - #{@provider.name_and_code}", @provider_partnership_form.errors.present?) %> + + <%= form_with( + model: @provider_partnership_form, + url: publish_provider_recruitment_cycle_accredited_partnerships_path, + method: :post + ) do |f| %> + + <%= f.govuk_error_summary %> + +
+
+ + <% content_for :before_content do %> + <%= govuk_back_link_to(publish_back_link_for_adding_provider_partnership_path(param_form_key: f.object_name.to_sym, params:, recruitment_cycle_year: @recruitment_cycle.year, provider: @provider)) %> + <% end %> + + <%= f.govuk_text_area( + :description, + label: { text: t(".title"), size: "l", tag: "h1" }, + hint: -> { render "hint", hint: t(".hint") }, + caption: { text: t(".caption"), size: "l" }, + max_words: 100, + rows: 10 + ) %> + + <%= f.hidden_field :accredited_provider_id %> + + <%= f.govuk_submit t("continue") %> + +

+ <%= govuk_link_to(t("cancel"), publish_provider_recruitment_cycle_accredited_partnerships_path) %> +

+
+
+<% end %> diff --git a/app/views/publish/providers/accredited_provider_search/new.html.erb b/app/views/publish/providers/accredited_provider_search/new.html.erb index 1613d7a2c2..2ee8868d7e 100644 --- a/app/views/publish/providers/accredited_provider_search/new.html.erb +++ b/app/views/publish/providers/accredited_provider_search/new.html.erb @@ -7,7 +7,7 @@ ) do |f| %> <% content_for :before_content do %> - <%= govuk_back_link_to(publish_back_link_for_adding_accrediting_provider_path(param_form_key: f.object_name.to_sym, params:, recruitment_cycle_year: @recruitment_cycle.year, provider: @provider)) %> + <%= govuk_back_link_to(accredited_provider_search_path(param_form_key: f.object_name.to_sym, params:, recruitment_cycle_year: @recruitment_cycle.year, provider: @provider)) %> <% end %> <%= f.govuk_error_summary %> @@ -38,7 +38,7 @@ <%= f.govuk_submit t("continue") %>

- <%= govuk_link_to(t("cancel"), publish_provider_recruitment_cycle_accredited_providers_path(@provider.provider_code, @provider.recruitment_cycle_year)) %> + <%= govuk_link_to(t("cancel"), accredited_provider_search_path(param_form_key: f.object_name.to_sym, params:, recruitment_cycle_year: @recruitment_cycle.year, provider: @provider)) %>

diff --git a/app/views/publish/providers/accredited_providers/new.html.erb b/app/views/publish/providers/accredited_providers/new.html.erb index d389e45095..66ef53b81c 100644 --- a/app/views/publish/providers/accredited_providers/new.html.erb +++ b/app/views/publish/providers/accredited_providers/new.html.erb @@ -12,7 +12,7 @@
<% content_for :before_content do %> - <%= govuk_back_link_to(publish_back_link_for_adding_accrediting_provider_path(param_form_key: f.object_name.to_sym, params:, recruitment_cycle_year: @recruitment_cycle.year, provider: @provider)) %> + <%= govuk_back_link_to(publish_back_link_for_adding_provider_partnership_path(param_form_key: f.object_name.to_sym, params:, recruitment_cycle_year: @recruitment_cycle.year, provider: @provider)) %> <% end %> <%= f.govuk_text_area( diff --git a/app/views/publish/providers/v2/training_providers/courses/index.html.erb b/app/views/publish/providers/v2/training_providers/courses/index.html.erb new file mode 100644 index 0000000000..363cbadf61 --- /dev/null +++ b/app/views/publish/providers/v2/training_providers/courses/index.html.erb @@ -0,0 +1,11 @@ +<% content_for :page_title, @provider.provider_name %> +<%= content_for :before_content, render_breadcrumbs(:training_provider_courses) %> + +

+ Training partner + <%= @training_provider.provider_name %> +

+ +
+ <%= render partial: "publish/courses/course_table", locals: { courses: @courses } %> +
diff --git a/app/views/publish/providers/v2/training_providers/index.html.erb b/app/views/publish/providers/v2/training_providers/index.html.erb new file mode 100644 index 0000000000..57c95c31dd --- /dev/null +++ b/app/views/publish/providers/v2/training_providers/index.html.erb @@ -0,0 +1,52 @@ +<% content_for :page_title, "Training partners" %> +<%= content_for :before_content, render_breadcrumbs(:training_providers) %> + +

+ Training partners +

+ +
+
+ +
    + <% @training_providers.each do |training_provider| %> +
  • +

    + <%= govuk_link_to( + training_provider.provider_name, + publish_provider_recruitment_cycle_training_provider_courses_path( + @provider.provider_code, + @provider.recruitment_cycle_year, + training_provider.provider_code + ), + class: "govuk-!-font-weight-bold", + data: { qa: "training_provider_name" } + ) %> + + <%= pluralize(@course_counts[training_provider.provider_code], "course") %> + +

    +
  • + <% end %> +
+
+ + <% unless @training_providers.empty? %> + + <% end %> +
diff --git a/app/views/support/providers/accredited_partners/_can_remove.html.erb b/app/views/support/providers/accredited_partners/_can_remove.html.erb new file mode 100644 index 0000000000..c7b5169ae7 --- /dev/null +++ b/app/views/support/providers/accredited_partners/_can_remove.html.erb @@ -0,0 +1,22 @@ +<%= content_for :page_title, t("support.providers.accredited_providers.delete.title") %> +<% content_for :before_content do %> + <%= govuk_back_link_to(support_recruitment_cycle_provider_accredited_partners_path) %> +<% end %> + +
+
+

+ <%= @accredited_provider.provider_name %> + <%= t("support.providers.accredited_partners.delete.title") %> +

+ + <%= govuk_button_to "Remove accredited partner", + delete_support_recruitment_cycle_provider_accredited_partner_path, + method: :delete, + class: "govuk-button--warning" %> + +

+ <%= govuk_link_to(t("cancel"), support_recruitment_cycle_provider_accredited_partners_path) %> +

+
+
diff --git a/app/views/support/providers/accredited_partners/_cannot_remove.html.erb b/app/views/support/providers/accredited_partners/_cannot_remove.html.erb new file mode 100644 index 0000000000..8eaf4cf7ff --- /dev/null +++ b/app/views/support/providers/accredited_partners/_cannot_remove.html.erb @@ -0,0 +1,23 @@ +<% content_for :page_title, "You cannot remove this accredited partner" %> +<% content_for :before_content do %> + <%= govuk_back_link_to(support_recruitment_cycle_provider_accredited_providers_path) %> +<% end %> + +
+
+

+ <%= @accredited_provider.provider_name %> + You cannot remove this accredited provider +

+ +

+ <%= @accredited_provider.provider_name %> is an + accredited partner for courses run by <%= @provider.provider_name %>. At least one of these courses is + currently published on Find. +

+ +

+ <%= govuk_link_to(t("cancel"), support_recruitment_cycle_provider_accredited_partners_path) %> +

+
+
diff --git a/app/views/support/providers/accredited_partners/checks/show.html.erb b/app/views/support/providers/accredited_partners/checks/show.html.erb new file mode 100644 index 0000000000..df89ab4966 --- /dev/null +++ b/app/views/support/providers/accredited_partners/checks/show.html.erb @@ -0,0 +1,42 @@ + +<%= render PageTitle.new( + title: "Check your answers - #{t('.caption', provider_name: @provider.provider_name, code: @provider.provider_code)}" +) %> + +<% content_for :before_content do %> + <%= govuk_back_link_to(new_support_recruitment_cycle_provider_accredited_partner_path) %> +<% end %> + +
+
+ + <%= form_with(url: check_support_recruitment_cycle_provider_accredited_partners_path, method: :put, local: true) do |f| %> +

+ <%= t(".caption", provider_name: @provider.provider_name, code: @provider.provider_code) %> + Check your answers +

+ + <%= render GovukComponent::SummaryListComponent.new do |component| + component.with_row do |row| + row.with_key { "Accredited provider" } + row.with_value { @accredited_provider_form.provider_name } + row.with_action(text: "Change", href: search_support_recruitment_cycle_provider_accredited_providers_path(goto_confirmation: true), visually_hidden_text: "accredited partner name") + end + + component.with_row do |row| + row.with_key { "About the accredited partner" } + row.with_value { @accredited_provider_form.description } + row.with_action(text: "Change", href: new_support_recruitment_cycle_provider_accredited_partner_path(goto_confirmation: true), visually_hidden_text: "accredited partner description") + end + end %> + + <%= govuk_warning_text(text: "All users at #{@accredited_provider_form.provider_name} will be sent an email to let them know they’ve been added.") %> + + <%= f.govuk_submit(t(".add")) %> + <% end %> + +

+ <%= govuk_link_to(t("cancel"), support_recruitment_cycle_provider_accredited_partners_path) %> +

+
+
diff --git a/app/views/support/providers/accredited_partners/delete.html.erb b/app/views/support/providers/accredited_partners/delete.html.erb new file mode 100644 index 0000000000..a6d881ade7 --- /dev/null +++ b/app/views/support/providers/accredited_partners/delete.html.erb @@ -0,0 +1 @@ +<%= render partial: @cannot_delete ? "cannot_remove" : "can_remove" %> diff --git a/app/views/support/providers/accredited_partners/edit.html.erb b/app/views/support/providers/accredited_partners/edit.html.erb new file mode 100644 index 0000000000..6592170509 --- /dev/null +++ b/app/views/support/providers/accredited_partners/edit.html.erb @@ -0,0 +1,41 @@ +<% content_for :page_title, title_with_error_prefix("About the accredited partnership - Edit accredited partnership - #{@provider.name_and_code}", @accredited_provider_form.errors.present?) %> + +
+
+ + <%= content_for(:breadcrumbs) do %> + <%= render GovukComponent::BackLinkComponent.new( + text: "Back", + href: support_recruitment_cycle_provider_accredited_partners_path( + recruitment_cycle_year: @recruitment_cycle.year, + provider_id: @provider.id + ) + ) %> + <% end %> + + <%= form_with( + model: @accredited_provider_form, + url: support_recruitment_cycle_provider_accredited_partner_path, + method: :put + ) do |f| %> + + <%= f.govuk_text_area( + :description, + label: { text: t(".title"), size: "l", tag: "h1" }, + hint: { text: t(".hint") }, + caption: { text: @accredited_provider_form.accredited_provider.provider_name, size: "l" }, + max_words: 100, + rows: 10 + ) %> + <%= f.hidden_field :accredited_provider_id, value: @accredited_provider_form.accredited_provider.id %> + + <%= f.govuk_submit "Update description" %> + +

+ <%= govuk_link_to(t("cancel"), support_recruitment_cycle_provider_accredited_partners_path) %> +

+ + <% end %> + +
+
diff --git a/app/views/support/providers/accredited_partners/index.html.erb b/app/views/support/providers/accredited_partners/index.html.erb new file mode 100644 index 0000000000..7708eb7960 --- /dev/null +++ b/app/views/support/providers/accredited_partners/index.html.erb @@ -0,0 +1,20 @@ +<%= render PageTitle.new(title: "support.providers.accredited_providers.index") %> + +<%= govuk_button_link_to("Add accredited partner", search_support_recruitment_cycle_provider_accredited_providers_path) %> + +<% if @accredited_partnerships.none? %> +

There are no accredited partnerships for <%= @provider.provider_name %>.

+<% else %> + <% @accredited_partnerships.each do |partnership| %> + <%= render AccreditedProviderComponent.new( + provider_name: govuk_link_to(partnership.accredited_provider.provider_name, support_recruitment_cycle_provider_path(partnership.accredited_provider.recruitment_cycle_year, partnership.accredited_provider)), + remove_path: delete_support_recruitment_cycle_provider_accredited_partner_path( + accredited_provider_code: partnership.accredited_provider.provider_code + ), + about_accredited_provider: partnership.description, + change_about_accredited_provider_path: edit_support_recruitment_cycle_provider_accredited_partner_path( + accredited_provider_code: partnership.accredited_provider.provider_code + ) + ) %> + <% end %> +<% end %> diff --git a/app/views/support/providers/accredited_partners/new.html.erb b/app/views/support/providers/accredited_partners/new.html.erb new file mode 100644 index 0000000000..085a4f15c0 --- /dev/null +++ b/app/views/support/providers/accredited_partners/new.html.erb @@ -0,0 +1,38 @@ +<% content_for :page_title, title_with_error_prefix("About the accredited partner - Add accredited partner - #{@provider.name_and_code}", @accredited_provider_form.errors.present?) %> + +
+
+ + <%= form_with( + model: @accredited_provider_form, + url: support_recruitment_cycle_provider_accredited_partners_path, + method: :post + ) do |f| %> + + <%= content_for(:breadcrumbs) do %> + <%= render GovukComponent::BackLinkComponent.new( + text: "Back", + href: back_link_for_adding_accredited_partner_path(param_form_key: f.object_name.to_sym, params:, recruitment_cycle_year: @recruitment_cycle.year, provider: @provider) + ) %> + <% end %> + + <%= f.govuk_error_summary %> + + <%= f.govuk_text_area( + :description, + label: { text: t(".title"), size: "l", tag: "h1" }, + hint: { text: t(".hint") }, + caption: { text: t(".caption", provider_name: @provider.provider_name, code: @provider.provider_code), size: "l" }, + max_words: 100, + rows: 10 + ) %> + + <%= f.hidden_field :accredited_provider_id, value: accredited_provider_id %> + <%= f.govuk_submit t("continue") %> + <% end %> + +

+ <%= govuk_link_to(t("cancel"), support_recruitment_cycle_provider_accredited_partners_path) %> +

+
+
diff --git a/app/views/support/providers/accredited_provider_search/new.html.erb b/app/views/support/providers/accredited_provider_search/new.html.erb index 5e7554162a..11a5625b0f 100644 --- a/app/views/support/providers/accredited_provider_search/new.html.erb +++ b/app/views/support/providers/accredited_provider_search/new.html.erb @@ -12,7 +12,7 @@ <%= content_for(:breadcrumbs) do %> <%= render GovukComponent::BackLinkComponent.new( text: "Back", - href: back_link_for_adding_accrediting_provider_path(param_form_key: f.object_name.to_sym, params:, recruitment_cycle_year: @recruitment_cycle.year, provider: @provider) + href: back_link_for_adding_accredited_partner_path(param_form_key: f.object_name.to_sym, params:, recruitment_cycle_year: @recruitment_cycle.year, provider: @provider) ) %> <% end %> @@ -39,7 +39,7 @@ <% end %>

- <%= govuk_link_to(t("cancel"), support_recruitment_cycle_provider_accredited_providers_path) %> + <%= govuk_link_to(t("cancel"), support_recruitment_cycle_provider_accredited_partners_path) %>

diff --git a/app/views/support/providers/accredited_providers/new.html.erb b/app/views/support/providers/accredited_providers/new.html.erb index dfdc34edc3..9491ef1acb 100644 --- a/app/views/support/providers/accredited_providers/new.html.erb +++ b/app/views/support/providers/accredited_providers/new.html.erb @@ -12,7 +12,7 @@ <%= content_for(:breadcrumbs) do %> <%= render GovukComponent::BackLinkComponent.new( text: "Back", - href: back_link_for_adding_accrediting_provider_path(param_form_key: f.object_name.to_sym, params:, recruitment_cycle_year: @recruitment_cycle.year, provider: @provider) + href: back_link_for_adding_accredited_partner_path(param_form_key: f.object_name.to_sym, params:, recruitment_cycle_year: @recruitment_cycle.year, provider: @provider) ) %> <% end %> diff --git a/config/locales/en.yml b/config/locales/en.yml index 13563409fd..f7a85c8682 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -131,6 +131,7 @@ en: training_partners: "Training partners" organisation_details: "Organisation details" accredited_provider: "Accredited providers" + accredited_partnerships: "Accredited partnerships" secondary_navigation: description: Description basic_details: Basic details @@ -648,6 +649,24 @@ en: new: title: *new_search cannot_find: *cannot_find + accredited_partnerships: + new: + title: About the accredited partnership + hint: Tell candidates about the accredited provider. You could mention their academic specialities and achievements. + caption: &add_accredited_partnership Add accredited partnership + edit: + title: About the accredited partnership + hint: Tell candidates about the accredited provider. You could mention their academic specialities and achievements. + updated: About the accredited partnership updated + delete: + title: Are you sure you want to remove this accredited partnership? + remove: Remove accredited partnership + updated: Accredited partnership removed + checks: + show: + title: *add_accredited_partnership + caption: *add_accredited_partnership + add: *add_accredited_partnership accredited_providers: new: title: About the accredited provider @@ -711,6 +730,24 @@ en: new: title: *accredited_provider_title caption: &accredited_provider_caption "Add accredited provider - %{provider_name} (%{code})" + accredited_partners: + new: + title: About the accredited partner + hint: Tell candidates about the accredited partner. You could mention their academic specialities and achievements. + caption: "Add accredited partner - %{provider_name} (%{code})" + edit: + title: About the accredited partner + hint: Tell candidates about the accredited partner. You could mention their academic specialities and achievements. + caption: "%{provider_name}" + updated: About the accredited partner updated + delete: + title: Are you sure you want to remove this accredited partner? + remove: Remove accredited partner + updated: Accredited partner removed + checks: + show: + caption: "Add accredited partner - %{provider_name} (%{code})" + add: Add accredited partner accredited_providers: new: title: About the accredited provider @@ -870,6 +907,9 @@ en: blank: "^Enter a course length" provider_partnership: attributes: + description: + blank: Enter details about the accredited partnership + too_long: Description about the accredited provider must be 100 words or fewer accredited_provider: format: "%{message}" taken: This partnership already exists @@ -947,6 +987,11 @@ en: attributes: provider_id: blank: Select an accredited provider + provider_partnership_form: + attributes: + description: + blank: Enter details about the accredited partnership + too_long: Description about the accredited provider must be 100 words or fewer accredited_provider_form: attributes: description: diff --git a/config/routes/publish.rb b/config/routes/publish.rb index fa087bb1fa..3ff097c772 100644 --- a/config/routes/publish.rb +++ b/config/routes/publish.rb @@ -125,10 +125,22 @@ resource :apprenticeship, on: :member, only: %i[new], controller: 'courses/apprenticeship' do get 'continue' end - resource :accredited_provider, on: :member, only: %i[new], controller: 'courses/accredited_provider', path: 'accredited-provider' do - get 'continue' - get 'search_new' + + # rubocop:disable Style/RedundantConstantBase + constraints(::Constraints::PartnershipFeature.new(:off)) do + resource :accredited_provider, on: :member, only: %i[new], controller: 'courses/accredited_provider', path: 'accredited-provider' do + get 'continue' + get 'search_new' + end + end + + constraints(::Constraints::PartnershipFeature.new(:on)) do + resource :ratifying_provider, on: :member, only: %i[new], controller: 'courses/ratifying_provider', path: 'ratifying-provider' do + get 'continue' + get 'search_new' + end end + # rubocop:enable Style/RedundantConstantBase resource :student_visa_sponsorship, on: :member, controller: 'courses/student_visa_sponsorship', path: 'student-visa-sponsorship' do get 'continue' end @@ -232,9 +244,19 @@ get '/apprenticeship', on: :member, to: 'courses/apprenticeship#edit' put '/apprenticeship', on: :member, to: 'courses/apprenticeship#update' - get '/accredited-provider', on: :member, to: 'courses/accredited_provider#edit' - put '/accredited-provider', on: :member, to: 'courses/accredited_provider#update' - get '/accredited-by', on: :member, to: 'courses/accredited_provider#show' + # rubocop:disable Style/RedundantConstantBase + constraints(::Constraints::PartnershipFeature.new(:off)) do + get '/accredited-provider', on: :member, to: 'courses/accredited_provider#edit' + put '/accredited-provider', on: :member, to: 'courses/accredited_provider#update' + get '/accredited-by', on: :member, to: 'courses/accredited_provider#show' + end + + constraints(::Constraints::PartnershipFeature.new(:on)) do + get '/ratifying-provider', on: :member, to: 'courses/ratifying_provider#edit' + put '/ratifying-provider', on: :member, to: 'courses/ratifying_provider#update', as: :ratifying_provider_publish_provider_recruitment_cycle_course + get '/ratified-by', on: :member, to: 'courses/ratifying_provider#show' + end + # rubocop:enable Style/RedundantConstantBase get '/provider', on: :member, to: 'courses/providers#show' @@ -256,19 +278,54 @@ resources :courses, module: :training_providers, only: [:index] end - resources :accredited_providers, param: :accredited_provider_code, only: %i[index new edit create update destroy], path: 'accredited-providers' do - member do - get :delete - delete :delete, to: 'accredited_providers#destroy' + # rubocop:disable Style/RedundantConstantBase + constraints(::Constraints::PartnershipFeature.new(:on)) do + get '/publish/organisations/:provider_code/:recruitment_cycle_year/accredited-providers', to: redirect('/publish/organisations/:provider_code/:recruitment_cycle_year/accredited-partnerships') + resources :accredited_partnerships, param: :accredited_provider_code, except: %i[show], path: 'accredited-partnerships', controller: 'accredited_partnerships' do + member do + get :delete + delete :delete, to: 'accredited_partnerships#destroy' + end + + get '/check', on: :collection, to: 'accredited_partnerships/checks#show' + put '/check', on: :collection, to: 'accredited_partnerships/checks#update' end + end + + constraints(::Constraints::PartnershipFeature.new(:off)) do + resources :accredited_providers, param: :accredited_provider_code, only: %i[index new edit create update destroy], path: 'accredited-providers' do + member do + get :delete + delete :delete, to: 'accredited_providers#destroy' + end + + get '/search', on: :collection, to: 'accredited_provider_search#new' + post '/search', on: :collection, to: 'accredited_provider_search#create' + put '/search', on: :collection, to: 'accredited_provider_search#update' + + get '/check', on: :collection, to: 'accredited_providers/checks#show' + put '/check', on: :collection, to: 'accredited_providers/checks#update' + end + end + scope ':recruitment_cycle_year/accredited-providers', as: :accredited_providers do get '/search', on: :collection, to: 'accredited_provider_search#new' post '/search', on: :collection, to: 'accredited_provider_search#create' put '/search', on: :collection, to: 'accredited_provider_search#update' + end - get '/check', on: :collection, to: 'accredited_providers/checks#show' - put '/check', on: :collection, to: 'accredited_providers/checks#update' + constraints(::Constraints::PartnershipFeature.new(:off)) do + resources :training_providers, path: '/training-providers', only: [:index], param: :code do + resources :courses, only: [:index], controller: 'training_providers/courses' + end + end + + constraints(::Constraints::PartnershipFeature.new(:on)) do + resources :training_providers, path: '/training-providers', controller: 'v2/training_providers', only: [:index], param: :code do + resources :courses, only: [:index], controller: 'v2/training_providers/courses' + end end + # rubocop:enable Style/RedundantConstantBase resource :check_school, only: %i[show update], controller: 'schools_check', path: 'schools/check' resources :schools do diff --git a/config/routes/support.rb b/config/routes/support.rb index 6d1be3b890..faa9c0f94d 100644 --- a/config/routes/support.rb +++ b/config/routes/support.rb @@ -44,20 +44,42 @@ end scope module: :providers do - resources :accredited_providers, param: :accredited_provider_code, only: %i[index new edit create update], path: 'accredited-providers' do - member do - get :delete - delete :delete, to: 'accredited_providers#destroy' + # rubocop:disable Style/RedundantConstantBase + constraints(::Constraints::PartnershipFeature.new(:off)) do + resources :accredited_providers, param: :accredited_provider_code, only: %i[index new edit create update], path: 'accredited-providers' do + member do + get :delete + delete :delete, to: 'accredited_providers#destroy' + end + get '/search', on: :collection, to: 'accredited_provider_search#new' + post '/search', on: :collection, to: 'accredited_provider_search#create' + put '/search', on: :collection, to: 'accredited_provider_search#update' + + get '/check', on: :collection, to: 'accredited_providers/checks#show' + put '/check', on: :collection, to: 'accredited_providers/checks#update' end - get '/search', on: :collection, to: 'accredited_provider_search#new' - post '/search', on: :collection, to: 'accredited_provider_search#create' - put '/search', on: :collection, to: 'accredited_provider_search#update' - get '/check', on: :collection, to: 'accredited_providers/checks#show' - put '/check', on: :collection, to: 'accredited_providers/checks#update' + resources :copy_courses, only: %i[new create] end - resources :copy_courses, only: %i[new create] + constraints(::Constraints::PartnershipFeature.new(:on)) do + resources :accredited_partners, param: :accredited_provider_code, only: %i[index new edit create update], path: 'accredited-partners' do + member do + get :delete + delete :delete, to: 'accredited_partners#destroy' + end + get '/check', on: :collection, to: 'accredited_partners/checks#show' + put '/check', on: :collection, to: 'accredited_partners/checks#update' + end + + resources :accredited_providers, param: :accredited_provider_code, only: %i[], path: 'accredited-providers' do + get '/search', on: :collection, to: 'accredited_provider_search#new' + post '/search', on: :collection, to: 'accredited_provider_search#create' + put '/search', on: :collection, to: 'accredited_provider_search#update' + end + resources :copy_courses, only: %i[new create] + end + # rubocop:enable Style/RedundantConstantBase end end resources :users do diff --git a/spec/components/add_course_button_preview.rb b/spec/components/add_course_button_preview.rb index 4c846198c7..31eca2322d 100644 --- a/spec/components/add_course_button_preview.rb +++ b/spec/components/add_course_button_preview.rb @@ -37,6 +37,10 @@ class FakeProvider include ActiveModel::Model attr_accessor(:study_sites, :accredited_providers, :sites) + def accredited_partners + [] + end + def provider_code 'DFE' end diff --git a/spec/factories/providers.rb b/spec/factories/providers.rb index 112a5688e1..4c462ada9f 100644 --- a/spec/factories/providers.rb +++ b/spec/factories/providers.rb @@ -41,6 +41,10 @@ provider_name { 'Test Name' } end + trait :with_accredited_partner do + accredited_partnerships { [association(:provider_partnership)] } + end + trait :university do provider_type { :university } urn { nil } diff --git a/spec/features/publish/accredited_partnership_spec.rb b/spec/features/publish/accredited_partnership_spec.rb new file mode 100644 index 0000000000..3453f5e65a --- /dev/null +++ b/spec/features/publish/accredited_partnership_spec.rb @@ -0,0 +1,290 @@ +# frozen_string_literal: true + +require 'rails_helper' + +feature 'Accredited partnership flow', { can_edit_current_and_next_cycles: false } do + before do + allow(Settings.features).to receive(:provider_partnerships).and_return(true) + given_i_am_a_lead_school_provider_user + and_i_visit_the_root_path + when_i_click_on_the_accredited_provider_tab + end + + scenario 'i can view the accredited providers tab when there are none' do + then_i_see_the_correct_text_for_no_accredited_providers + end + + scenario 'i can view accredited partnerships on the index page' do + and_my_provider_has_accrediting_providers + and_i_click_on_the_accredited_provider_tab + then_i_should_see_the_accredited_provider_name_displayed + end + + scenario 'i can edit accredited partnerships on the index page' do + and_my_provider_has_accrediting_providers + and_i_click_on_the_accredited_provider_tab + and_i_click_change + + when_i_input_some_different_information + then_i_should_see_the_different_information + and_i_see_the_success_message + end + + scenario 'i cannot delete accredited providers if they are attached to a course' do + and_my_provider_has_accrediting_providers + and_i_click_on_the_accredited_provider_tab + and_i_click_remove + then_i_should_see_the_cannot_remove_ap_text + end + + scenario 'i can delete accredited providers if they are not attached to a course' do + and_i_create_a_new_accredited_provider + and_i_click_remove + and_i_click_remove_ap + and_i_see_the_remove_success_message + then_i_should_be_taken_to_the_index_page + end + + scenario 'i can create a new provider partnership' do + given_there_are_accredited_providers_in_the_database_with_users + when_i_click_add_accredited_provider + and_i_search_with_an_invalid_query + then_i_should_see_an_error_message + + when_i_search_for_an_accredited_provider_with_a_valid_query + then_i_see_the_provider_i_searched_for + + when_i_continue_without_selecting_an_accredited_provider + and_i_should_see_an_error_message('Select an accredited provider') + then_i_should_still_see_the_provider_i_searched_for + + when_i_select_the_provider + and_i_continue_without_entering_a_description + then_i_should_see_an_error_message('Enter details about the accredited partnership') + + when_i_input_some_information + then_i_should_see_the_information_i_added + + when_i_confirm_the_changes + then_i_should_be_taken_to_the_index_page + and_the_accredited_provider_is_saved_to_the_database + and_i_should_see_a_success_message + and_i_should_see_the_accredited_providers + end + + scenario 'back links behaviour' do + given_i_am_on_the_confirm_page + when_i_click_the_change_link_for('accredited provider name') + then_i_should_be_taken_to_the_accredited_provider_search_page + + when_i_click_the_back_link + then_i_should_be_taken_back_to_the_confirm_page + + when_i_click_the_change_link_for('accredited provider description') + then_i_should_be_taken_to_the_accredited_provider_description_page + + when_i_click_the_back_link + then_i_should_be_taken_back_to_the_confirm_page + end + + private + + def and_i_click_remove_ap + click_link_or_button 'Remove accredited partnership' + end + + def then_i_should_see_the_cannot_remove_ap_text + expect(page).to have_css('h1', text: 'You cannot remove this accredited provider') + end + + def and_i_click_remove + click_link_or_button 'Remove' + end + + def and_i_create_a_new_accredited_provider + given_there_are_accredited_providers_in_the_database_with_users + when_i_click_add_accredited_provider + when_i_search_for_an_accredited_provider_with_a_valid_query + when_i_select_the_provider + when_i_input_some_information + when_i_confirm_the_changes + end + + def and_i_click_change + click_link_or_button('Change') + end + + def and_i_should_see_the_accredited_providers + expect(page).to have_css('.govuk-summary-card', count: 1) + expect(page).to have_content(@accredited_provider.provider_name) + end + + def and_the_accredited_provider_is_saved_to_the_database + @provider.reload + expect(@provider.accredited_partners.count).to eq(1) + expect(@provider.accredited_partners.first.id).to eq(@accredited_provider.id) + end + + def then_i_should_be_taken_to_the_accredited_provider_description_page + expect(page).to have_current_path(new_publish_provider_recruitment_cycle_accredited_partnership_path(@provider.provider_code, @provider.recruitment_cycle_year, goto_confirmation: true)) + end + + def then_i_should_be_taken_back_to_the_confirm_page + expect(page).to have_current_path(check_publish_provider_recruitment_cycle_accredited_partnerships_path(@provider.provider_code, @provider.recruitment_cycle_year)) + end + + def when_i_click_the_back_link + click_link_or_button 'Back' + end + + def then_i_should_be_taken_to_the_accredited_provider_search_page + expect(page).to have_current_path( + search_publish_provider_recruitment_cycle_accredited_providers_path(@provider.provider_code, @provider.recruitment_cycle_year, goto_confirmation: true) + ) + end + + def when_i_click_the_change_link_for(field) + within '.govuk-summary-list' do + click_link_or_button "Change #{field}" + end + end + + def given_i_am_on_the_confirm_page + given_there_are_accredited_providers_in_the_database_with_users + when_i_click_add_accredited_provider + when_i_search_for_an_accredited_provider_with_a_valid_query + when_i_select_the_provider + when_i_input_some_information + end + + def and_i_should_see_a_success_message + expect(page).to have_content('Accredited partnership added') + end + + def and_i_see_the_success_message + expect(page).to have_content('About the accredited partnership updated') + end + + def and_i_see_the_remove_success_message + expect(page).to have_content('Accredited partnership removed') + end + + def then_i_should_be_taken_to_the_index_page + expect(page).to have_current_path(publish_provider_recruitment_cycle_accredited_partnerships_path(@provider.provider_code, @provider.recruitment_cycle_year)) + end + + def when_i_confirm_the_changes + expect do + click_link_or_button 'Add accredited partnership' + end.to have_enqueued_email(Users::OrganisationMailer, :added_as_an_organisation_to_training_partner) + end + + def then_i_should_see_the_information_i_added + expect(page).to have_text('This is a description') + end + + def then_i_should_see_the_different_information + expect(page).to have_text('updates to the AP description') + end + + alias_method :then_i_should_see_the_description, :then_i_should_see_the_information_i_added + + def when_i_input_some_information + fill_in 'About the accredited partnership', with: 'This is a description' + click_continue + end + + def when_i_input_some_different_information + fill_in 'About the accredited partnership', with: 'updates to the AP description' + click_link_or_button 'Update description' + end + + def and_i_search_with_an_invalid_query + fill_in form_title, with: '' + click_continue + end + + def when_i_select_the_provider + choose @accredited_provider.provider_name + click_continue + end + + def then_i_should_still_see_the_provider_i_searched_for + expect(page).to have_content(@accredited_provider.provider_name) + expect(page).to have_no_content(@accredited_provider_two.provider_name) + expect(page).to have_no_content(@accredited_provider_three.provider_name) + end + + def and_i_should_see_an_error_message(error_message = form_title) + expect(page).to have_content(error_message) + end + + alias_method :then_i_should_see_an_error_message, :and_i_should_see_an_error_message + + def when_i_continue_without_selecting_an_accredited_provider + click_continue + end + + def then_i_see_the_provider_i_searched_for + expect(page).to have_content(@accredited_provider.provider_name) + expect(page).to have_no_content(@accredited_provider_two.provider_name) + expect(page).to have_no_content(@accredited_provider_three.provider_name) + end + + def given_there_are_accredited_providers_in_the_database_with_users + user = create(:user) + @accredited_provider = create(:provider, :accredited_provider, provider_name: 'UCL') + @accredited_provider.users << user + @accredited_provider_two = create(:provider, :accredited_provider, provider_name: 'Accredited provider two') + @accredited_provider_three = create(:provider, :accredited_provider, provider_name: 'Accredited provider three') + end + + def when_i_search_for_an_accredited_provider_with_a_valid_query + fill_in form_title, with: @accredited_provider.provider_name + click_continue + end + + def when_i_click_add_accredited_provider + click_link_or_button 'Add accredited partnership' + end + + def then_i_see_the_correct_text_for_no_accredited_providers + expect(page).to have_text("There are no accredited providers for #{@provider.provider_name}") + end + + def when_i_click_on_the_accredited_provider_tab + click_link_or_button 'Accredited partnership' + end + + alias_method :and_i_click_on_the_accredited_provider_tab, :when_i_click_on_the_accredited_provider_tab + + def and_i_visit_the_root_path + visit root_path + end + + def given_i_am_a_lead_school_provider_user + given_i_am_authenticated(user: create(:user, :with_provider)) + @provider = @current_user.providers.first + end + + def form_title + 'Enter a provider name, UKPRN or postcode' + end + + def click_continue + click_link_or_button 'Continue' + end + + alias_method :and_i_continue_without_entering_a_description, :click_continue + + def and_my_provider_has_accrediting_providers + course = build(:course, accrediting_provider: build(:provider, :accredited_provider, provider_name: 'Accrediting provider name')) + + @provider.courses << course + @provider.accredited_partnerships.create(accredited_provider: course.accrediting_provider, description: 'Great provider!') + end + + def then_i_should_see_the_accredited_provider_name_displayed + expect(page).to have_css('h2', text: 'Accrediting provider name') + end +end diff --git a/spec/features/publish/accredited_provider_spec.rb b/spec/features/publish/accredited_provider_spec.rb index 4dc5b09d2e..f60ec8a6d7 100644 --- a/spec/features/publish/accredited_provider_spec.rb +++ b/spec/features/publish/accredited_provider_spec.rb @@ -4,6 +4,7 @@ feature 'Accredited provider flow', { can_edit_current_and_next_cycles: false } do before do + allow(Settings.features).to receive(:provider_partnerships).and_return(false) given_i_am_a_lead_school_provider_user and_i_visit_the_root_path when_i_click_on_the_accredited_provider_tab diff --git a/spec/features/publish/courses/add_accredited_provider_when_publishing_a_course_spec.rb b/spec/features/publish/courses/add_accredited_provider_when_publishing_a_course_spec.rb index 0e56ce6491..bd68378a65 100644 --- a/spec/features/publish/courses/add_accredited_provider_when_publishing_a_course_spec.rb +++ b/spec/features/publish/courses/add_accredited_provider_when_publishing_a_course_spec.rb @@ -4,6 +4,7 @@ feature 'Publishing a course when course accrediting provider is invalid', { can_edit_current_and_next_cycles: false } do before do + allow(Settings.features).to receive(:provider_partnerships).and_return(false) given_i_am_authenticated_as_a_provider_user end diff --git a/spec/features/publish/courses/add_ratifying_provider_when_publishing_a_course_spec.rb b/spec/features/publish/courses/add_ratifying_provider_when_publishing_a_course_spec.rb new file mode 100644 index 0000000000..bbf29d858e --- /dev/null +++ b/spec/features/publish/courses/add_ratifying_provider_when_publishing_a_course_spec.rb @@ -0,0 +1,170 @@ +# frozen_string_literal: true + +require 'rails_helper' + +feature 'Publishing a course when course accrediting provider is invalid', { can_edit_current_and_next_cycles: false } do + before do + allow(Settings.features).to receive(:provider_partnerships).and_return(true) + given_i_am_authenticated_as_a_provider_user + end + + scenario 'Add accrediting provider to provider and provider has no accrediting providers, change accrediting provider of course then publish' do + and_the_provider_has_no_accredited_provider + and_there_is_a_draft_course_with_an_unaccredited_provider + + # Publising is invalid + when_i_visit_the_course_page + and_i_click_the_publish_button + then_i_should_see_an_error_message_that_accredited_provider_is_not_accredited + + # Add accrediting provider to provider + when_i_click_the_error_message_link + then_it_takes_me_to_the_accredited_providers_page + when_i_click_add_an_accredited_provider + and_i_search_for_an_accredited_provider + and_i_fill_in_the_accredited_provider_form + and_i_confirm_creation_of_the_accredited_provider + then_i_see_that_the_accredited_provider_has_been_added + + # Publishing is invalid + when_i_visit_the_course_page + and_i_click_the_publish_button + then_i_should_see_an_error_message_that_accredited_provider_is_not_accredited + + # Clicking error message allows user to select accrediting provider + when_i_click_the_error_message_link + and_i_choose_the_new_accredited_provider + and_i_click_the_publish_button + then_i_should_see_a_success_message + end + + scenario 'Select valid accrediting provider to course and publish' do + and_the_provider_has_a_valid_accrediting_provider + and_there_is_a_draft_course_without_accrediting_provider + and_an_accredited_provider_exists + + # Publising is invalid + when_i_visit_the_course_page + and_i_click_the_publish_button + then_i_should_see_an_error_message_for_the_accrediting_provider + + # Clicking error message allows user to select accrediting provider + when_i_click_the_select_accredited_provider_error_message_link + and_i_choose_the_new_accredited_provider + and_i_click_the_publish_button + then_i_should_see_a_success_message + end + + def given_i_am_authenticated_as_a_provider_user + @user = create(:user, :with_provider) + given_i_am_authenticated(user: @user) + end + + def and_the_provider_has_a_valid_accrediting_provider + provider = @user.providers.first + provider.accredited_partnerships.create(accredited_provider: accredited_provider, description: 'Description') + end + + def and_the_provider_has_no_accredited_provider + expect(provider.accredited_providers).to be_empty + end + + def and_there_is_a_draft_course_without_accrediting_provider + given_a_course_exists( + :with_gcse_equivalency, + enrichments: [create(:course_enrichment, :initial_draft)], + sites: [create(:site, location_name: 'location 1')], + study_sites: [create(:site, :study_site)] + ) + end + + def and_there_is_a_draft_course_with_an_unaccredited_provider + given_a_course_exists( + :with_gcse_equivalency, + accrediting_provider: provider, + enrichments: [create(:course_enrichment, :initial_draft)], + sites: [create(:site, location_name: 'location 1')], + study_sites: [create(:site, :study_site)] + ) + end + + def when_i_visit_the_course_page + publish_provider_courses_show_page.load( + provider_code: provider.provider_code, + recruitment_cycle_year: provider.recruitment_cycle_year, + course_code: course.course_code + ) + end + + def then_i_should_see_a_success_message + expect(page).to have_content('Your course has been published.') + end + + def then_i_should_see_an_error_message_that_accredited_provider_is_not_accredited + expect(publish_provider_courses_show_page.error_messages).to include('Update the accredited provider') + end + + def then_i_should_see_an_error_message_for_the_accrediting_provider + expect(publish_provider_courses_show_page.error_messages).to include('Select an accredited provider') + end + + def when_i_click_the_error_message_link + publish_provider_courses_show_page.errors.first.link.click + end + + def then_it_takes_me_to_the_accredited_providers_page + expect(publish_courses_ratifying_providers_page).to be_displayed + end + + def when_i_click_add_an_accredited_provider + publish_courses_accredited_providers_page.add_new_link.click + expect(publish_provider_accredited_providers_search_page).to be_displayed + end + + def and_i_search_for_an_accredited_provider + publish_provider_accredited_providers_search_page.search_input.set(accredited_provider.provider_name) + publish_provider_accredited_providers_search_page.continue_button.click + choose accredited_provider.name_and_code + publish_provider_accredited_providers_search_page.continue_button.click + end + + def and_i_fill_in_the_accredited_provider_form + publish_courses_new_accredited_provider_page.about_section_input.set('About course') + + publish_courses_new_accredited_provider_page.submit.click + end + + def and_i_confirm_creation_of_the_accredited_provider + publish_courses_new_accredited_provider_page.submit.click + end + + def then_i_see_that_the_accredited_provider_has_been_added + expect(page).to have_content('Accredited partnership added') + end + + def and_i_click_the_publish_button + publish_provider_courses_show_page.publish_button.click + end + + def when_i_click_the_select_accredited_provider_error_message_link + page.click_link_or_button('Select an accredited provider') + end + + def and_i_choose_the_new_accredited_provider + choose accredited_provider.provider_name + page.click_link_or_button('Update ratifying partner') + expect(page).to have_content('Accredited provider updated') + end + + def and_an_accredited_provider_exists + accredited_provider + end + + def accredited_provider + @accredited_provider ||= create(:provider, :accredited_provider) + end + + def provider + @current_user.providers.first + end +end 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 diff --git a/spec/features/publish/courses/adding_an_accredited_provider_to_an_unpublished_course_spec.rb b/spec/features/publish/courses/adding_an_accredited_provider_to_an_unpublished_course_spec.rb index a1764de28e..2728eb4bba 100644 --- a/spec/features/publish/courses/adding_an_accredited_provider_to_an_unpublished_course_spec.rb +++ b/spec/features/publish/courses/adding_an_accredited_provider_to_an_unpublished_course_spec.rb @@ -3,6 +3,10 @@ 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(false) + 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 diff --git a/spec/features/publish/courses/new_accredited_provider_spec.rb b/spec/features/publish/courses/new_accredited_provider_spec.rb index 2c952020a2..507ea08d8d 100644 --- a/spec/features/publish/courses/new_accredited_provider_spec.rb +++ b/spec/features/publish/courses/new_accredited_provider_spec.rb @@ -4,6 +4,7 @@ feature 'selection accredited_bodies', { can_edit_current_and_next_cycles: false } do before do + allow(Settings.features).to receive(:provider_partnerships).and_return(false) given_i_am_authenticated_as_a_provider_user when_i_visit_the_new_accredited_providers_page end diff --git a/spec/features/publish/courses/new_schools_enrichments_spec.rb b/spec/features/publish/courses/new_schools_enrichments_spec.rb new file mode 100644 index 0000000000..d262e715d3 --- /dev/null +++ b/spec/features/publish/courses/new_schools_enrichments_spec.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +require 'rails_helper' + +feature 'selection schools', { can_edit_current_and_next_cycles: false } do + before do + allow(Settings.features).to receive(:provider_partnerships).and_return(false) + given_i_am_authenticated_as_a_provider_user + and_that_sites_exist + when_i_visit_the_publish_courses_new_schools_page + end + + scenario 'selecting multiple schools' do + when_i_select_a_school + and_i_click_continue + then_i_am_met_with_the_accredited_provider_page + end + + scenario 'invalid entries' do + and_i_click_continue + then_i_am_met_with_errors + end + + private + + def given_i_am_authenticated_as_a_provider_user + @user = create(:user, :with_provider) + given_i_am_authenticated(user: @user) + end + + def and_that_sites_exist + provider.sites << create_list(:site, 3) + end + + def when_i_visit_the_publish_courses_new_schools_page + publish_courses_new_schools_page.load(provider_code: provider.provider_code, recruitment_cycle_year: Settings.current_recruitment_cycle_year, query: schools_params) + end + + def when_i_select_a_school + publish_courses_new_schools_page.check(provider.sites.first.location_name) + publish_courses_new_schools_page.check(provider.sites.second.location_name) + end + + def and_i_click_continue + publish_courses_new_schools_page.continue.click + end + + def provider + @provider ||= @user.providers.first + end + + def then_i_am_met_with_the_accredited_provider_page + expect(page).to have_current_path("/publish/organisations/#{provider.provider_code}/#{Settings.current_recruitment_cycle_year}/courses/accredited-provider/new", ignore_query: true) + expect(page).to have_content('Accredited provider') + end + + def then_i_am_met_with_errors + expect(page).to have_content('There is a problem') + expect(page).to have_content('Select at least one school') + end +end diff --git a/spec/features/publish/courses/new_schools_spec.rb b/spec/features/publish/courses/new_schools_spec.rb index 1f33ef0bac..6baf9685fa 100644 --- a/spec/features/publish/courses/new_schools_spec.rb +++ b/spec/features/publish/courses/new_schools_spec.rb @@ -4,6 +4,7 @@ feature 'selection schools', { can_edit_current_and_next_cycles: false } do before do + allow(Settings.features).to receive(:provider_partnerships).and_return(true) given_i_am_authenticated_as_a_provider_user and_that_sites_exist when_i_visit_the_publish_courses_new_schools_page @@ -49,8 +50,8 @@ def provider end def then_i_am_met_with_the_accredited_provider_page - expect(page).to have_current_path("/publish/organisations/#{provider.provider_code}/#{Settings.current_recruitment_cycle_year}/courses/accredited-provider/new", ignore_query: true) - expect(page).to have_content('Accredited provider') + expect(page).to have_current_path("/publish/organisations/#{provider.provider_code}/#{Settings.current_recruitment_cycle_year}/courses/ratifying-provider/new", ignore_query: true) + expect(page).to have_content('Ratifying provider') end def then_i_am_met_with_errors diff --git a/spec/features/publish/courses/new_tda_course_spec.rb b/spec/features/publish/courses/new_tda_course_spec.rb index 78887ef842..3a656a1c60 100644 --- a/spec/features/publish/courses/new_tda_course_spec.rb +++ b/spec/features/publish/courses/new_tda_course_spec.rb @@ -3,6 +3,10 @@ require 'rails_helper' feature 'Adding a teacher degree apprenticeship course', :can_edit_current_and_next_cycles do + before do + allow(Settings.features).to receive(:provider_partnerships).and_return(false) + end + scenario 'creating a degree awarding course from school direct provider' do given_i_am_authenticated_as_a_school_direct_provider_user when_i_visit_the_courses_page diff --git a/spec/features/publish/courses/new_tda_ratifying_course_spec.rb b/spec/features/publish/courses/new_tda_ratifying_course_spec.rb new file mode 100644 index 0000000000..768552890d --- /dev/null +++ b/spec/features/publish/courses/new_tda_ratifying_course_spec.rb @@ -0,0 +1,665 @@ +# frozen_string_literal: true + +require 'rails_helper' + +feature 'Adding a teacher degree apprenticeship course', :can_edit_current_and_next_cycles do + before do + allow(Settings.features).to receive(:provider_partnerships).and_return(true) + end + + scenario 'creating a degree awarding course from school direct provider' do + given_i_am_authenticated_as_a_school_direct_provider_user + when_i_visit_the_courses_page + and_i_click_on_add_course + and_i_choose_a_secondary_course + and_i_select_a_subject + and_i_choose_an_age_range + then_i_see_the_degree_awarding_option + + when_i_choose_a_degree_awarding_qualification + + # We skip the pages for the TDA: funding type, part-time/full time + then_i_am_on_the_choose_schools_page + + when_i_choose_the_school + and_i_choose_the_study_site + + # We skip the visa sponsorship question + then_i_am_on_the_add_applications_open_date_page + + when_i_choose_the_applications_open_date + and_i_choose_the_first_start_date + then_i_am_on_the_check_your_answers_page + and_i_can_not_change_funding_type + and_i_can_not_change_study_mode + and_i_can_not_change_visa_requirements + then_i_do_not_see_the_change_links_for_study_mode_funding_type_and_visa_sponsorship + + when_i_click_on_add_a_course + then_the_tda_course_is_created + and_the_tda_defaults_are_saved + + when_i_click_on_the_course_i_created + then_i_do_not_see_the_change_links_for_study_mode_funding_type_and_visa_sponsorship_on_basic_details + + when_i_click_on_the_course_description_tab + then_i_do_not_see_the_degree_requirements_row + and_i_do_not_see_the_change_link_for_course_length + + given_i_fill_in_all_other_fields_for_the_course + and_i_add_a_level_requirements + when_i_publish_the_course + then_the_course_is_published + end + + scenario 'creating a degree awarding course from scitt provider' do + given_i_am_authenticated_as_a_scitt_provider_user + when_i_visit_the_courses_page + and_i_click_on_add_course + and_i_choose_a_secondary_course + and_i_select_a_subject + and_i_choose_an_age_range + then_i_see_the_degree_awarding_option + + when_i_choose_a_degree_awarding_qualification + # We skip the pages for the TDA: funding type, part-time/full time + then_i_am_on_the_choose_schools_page + + when_i_choose_the_school + and_i_choose_the_study_site + # We skip the visa sponsorship question + then_i_am_on_the_add_applications_open_date_page + + when_i_choose_the_applications_open_date + and_i_choose_the_first_start_date + then_i_am_on_the_check_your_answers_page + and_i_do_not_see_the_change_links_for_study_mode_funding_type_and_visa_sponsorship + + when_i_click_on_add_a_course + then_the_tda_course_is_created + and_the_tda_defaults_are_saved + + when_i_click_on_the_course_i_created + then_i_do_not_see_the_change_links_for_study_mode_funding_type_and_visa_sponsorship_on_basic_details + + when_i_click_on_the_course_description_tab + then_i_do_not_see_the_degree_requirements_row + and_i_do_not_see_the_change_link_for_course_length + + given_i_fill_in_all_other_fields_for_the_course + and_i_add_a_level_requirements + when_i_publish_the_course + then_the_course_is_published + end + + scenario 'when choosing primary course' do + given_i_am_authenticated_as_a_school_direct_provider_user + when_i_visit_the_courses_page + and_i_click_on_add_course + and_i_choose_a_primary_course + and_i_choose_a_primary_age_range + then_i_see_the_degree_awarding_option + + when_i_choose_a_degree_awarding_qualification + # We skip the pages for the TDA: funding type, part-time/full time + then_i_am_on_the_choose_schools_page + + when_i_choose_the_school + and_i_choose_the_study_site + # We skip the visa sponsorship question + then_i_am_on_the_add_applications_open_date_page + + when_i_choose_the_applications_open_date + and_i_choose_the_first_start_date + then_i_am_on_the_check_your_answers_page + and_i_do_not_see_the_change_links_for_study_mode_funding_type_and_visa_sponsorship + + when_i_click_on_add_a_course + then_the_tda_course_is_created + and_the_tda_defaults_are_saved + + when_i_click_on_the_course_i_created + then_i_do_not_see_the_change_links_for_study_mode_funding_type_and_visa_sponsorship_on_basic_details + + when_i_click_on_the_course_description_tab + then_i_do_not_see_the_degree_requirements_row + and_i_do_not_see_the_change_link_for_course_length + + given_i_fill_in_all_other_fields_for_the_course + and_i_add_a_level_requirements + when_i_publish_the_course + then_the_course_is_published + end + + scenario 'do not show teacher degree apprenticeship for further education' do + given_i_am_authenticated_as_a_school_direct_provider_user + when_i_visit_the_courses_page + and_i_click_on_add_course + and_i_choose_a_further_education_course + then_i_am_on_the_qualifications_page + and_i_do_not_see_the_degree_awarding_option + end + + scenario 'back links when choosing a teacher degree apprenticeship' do + given_i_am_authenticated_as_a_school_direct_provider_user + when_i_visit_the_courses_page + and_i_click_on_add_course + and_i_choose_a_primary_course + and_i_choose_a_primary_age_range + then_i_see_the_degree_awarding_option + + when_i_choose_a_degree_awarding_qualification + # We skip the pages for the TDA: funding type, part-time/full time + then_i_am_on_the_choose_schools_page + and_the_back_link_points_to_outcome_page + + when_i_choose_the_school + then_the_back_link_points_to_the_school_page + and_i_choose_the_study_site + # We skip the visa sponsorship question + then_i_am_on_the_add_applications_open_date_page + and_the_back_link_points_to_the_study_site_page + + when_i_choose_the_applications_open_date + and_the_back_link_points_to_applications_open_date_page + and_i_choose_the_first_start_date + and_the_back_link_points_to_start_date_page + then_i_am_on_the_check_your_answers_page + end + + scenario 'creating a tda course then changing it to a non tda fee paying course' do + given_i_am_on_the_check_answers_page_of_a_new_tda_course + when_i_visit_the_course_outcome_page + and_the_back_link_points_to_the_confirm_page + + and_i_choose_qts + and_the_back_link_points_to_the_qualification_page + + and_i_choose_fee + and_the_back_link_points_to_the_funding_type_page + + and_i_choose_part_time + and_the_back_link_points_to_the_study_mode_page + + when_i_click_back + then_i_am_on_the_study_mode_page + + when_i_click_back + then_i_am_on_the_funding_type_page + + when_i_click_continue + and_i_click_continue + and_i_choose_to_sponsor_a_student_visa + when_i_click_on_add_a_course + then_i_see_the_correct_attributes_in_the_database_for_fee_paying + end + + scenario 'creating a tda course then changing it to a non tda salaried course' do + given_i_am_on_the_check_answers_page_of_a_new_tda_course + when_i_visit_the_course_outcome_page + and_i_choose_qts + and_the_back_link_points_to_the_qualification_page + and_i_choose_salaried + and_the_back_link_points_to_the_funding_type_page + and_i_choose_part_time + and_the_back_link_points_to_the_study_mode_page + when_i_click_back + then_i_am_on_the_study_mode_page + + when_i_click_back + then_i_am_on_the_funding_type_page + + when_i_click_continue + and_i_click_continue + + and_i_choose_to_sponsor_a_skilled_worker_visa + when_i_click_on_add_a_course + then_i_see_the_correct_attributes_in_the_database_for_salaried + end + + def given_i_am_authenticated_as_a_school_direct_provider_user + @user = create(:user, providers: [build(:provider, sites: [build(:site), build(:site)], study_sites: [build(:site, :study_site), build(:site, :study_site)])]) + @provider = @user.providers.first + create(:accredited_provider, provider_code: '1BJ') + @accredited_provider = create(:accredited_provider, provider_code: '1BK') + @provider.accredited_partnerships.create(accredited_provider: @accredited_provider, description: 'description') + + given_i_am_authenticated(user: @user) + end + + def given_i_am_authenticated_as_a_scitt_provider_user + @user = create( + :user, + providers: [ + create(:accredited_provider, :scitt, sites: [build(:site), build(:site)], study_sites: [build(:site, :study_site), build(:site, :study_site)]) + ] + ) + given_i_am_authenticated( + user: @user + ) + end + + def when_i_visit_the_courses_page + publish_provider_courses_index_page.load( + provider_code: provider.provider_code, + recruitment_cycle_year: provider.recruitment_cycle_year + ) + end + + def and_i_click_on_add_course + click_on 'Add course' + and_i_click_continue + end + + def and_i_choose_a_secondary_course + choose 'Secondary' + and_i_select_no_send + and_i_click_continue + end + + def and_i_choose_a_further_education_course + choose 'Further education' + and_i_select_no_send + and_i_click_continue + end + + def and_i_choose_a_primary_course + choose 'Primary' + and_i_select_no_send + and_i_click_continue + choose 'Primary with English' + and_i_click_continue + end + + def and_i_select_a_subject + select 'Dance', from: 'First subject' + and_i_click_continue + end + + def and_i_choose_an_age_range + choose '14 to 19' + and_i_click_continue + end + + def and_i_choose_a_primary_age_range + choose '3 to 7' + and_i_click_continue + end + + def and_i_click_continue + click_on 'Continue' + end + + def then_i_see_the_degree_awarding_option + expect( + publish_courses_new_outcome_page.qualification_fields.has_undergraduate_degree_with_qts? + ).to be true + expect(publish_courses_new_outcome_page.qualification_fields.text).to include( + 'Teacher degree apprenticeship (TDA) with QTS' + ) + end + + def then_i_am_on_the_qualifications_page + expect(page).to have_current_path(new_publish_provider_recruitment_cycle_courses_outcome_path(provider_code: provider.provider_code, recruitment_cycle_year:), ignore_query: true) + end + + def and_i_do_not_see_the_degree_awarding_option + expect( + publish_courses_new_outcome_page.qualification_fields.has_undergraduate_degree_with_qts? + ).to be false + end + + def when_i_choose_a_degree_awarding_qualification + choose 'Teacher degree apprenticeship (TDA) with QTS' + and_i_click_continue + end + + def then_i_am_on_the_choose_schools_page + expect(page).to have_current_path(new_publish_provider_recruitment_cycle_courses_schools_path(provider_code: provider.provider_code, recruitment_cycle_year:), ignore_query: true) + end + + def and_the_back_link_points_to_outcome_page + expect(publish_courses_new_outcome_page.back_link[:href]).to include(new_publish_provider_recruitment_cycle_courses_outcome_path(provider_code: provider.provider_code, recruitment_cycle_year:)) + end + + def when_i_choose_the_school + check provider.sites.first.location_name + and_i_click_continue + end + + def then_the_back_link_points_to_the_school_page + expect(publish_courses_new_study_sites_page.back_link[:href]).to include(back_publish_provider_recruitment_cycle_courses_schools_path(provider_code: provider.provider_code, recruitment_cycle_year:)) + end + + def and_i_choose_the_study_site + check provider.study_sites.first.location_name + and_i_click_continue + end + + def and_the_back_link_points_to_the_study_site_page + expect(publish_courses_new_applications_open_page.back_link[:href]).to include(back_publish_provider_recruitment_cycle_courses_study_sites_path(provider_code: provider.provider_code, recruitment_cycle_year:)) + end + + def then_i_am_on_the_add_applications_open_date_page + expect(page).to have_current_path(new_publish_provider_recruitment_cycle_courses_applications_open_path(provider_code: provider.provider_code, recruitment_cycle_year:), ignore_query: true) + end + + def and_the_back_link_points_to_applications_open_date_page + expect(publish_courses_new_start_date_page.back_link[:href]).to include(new_publish_provider_recruitment_cycle_courses_applications_open_path(provider_code: provider.provider_code, recruitment_cycle_year:)) + end + + def when_i_choose_the_applications_open_date + first('input.govuk-radios__input').set(true) + and_i_click_continue + end + + def and_i_choose_the_first_start_date + first('input.govuk-radios__input').set(true) + and_i_click_continue + end + + def and_the_back_link_points_to_start_date_page + expect(publish_course_confirmation_page.back_link[:href]).to include(new_publish_provider_recruitment_cycle_courses_start_date_path(provider_code: provider.provider_code, recruitment_cycle_year:)) + end + + def then_i_am_on_the_check_your_answers_page + expect(page).to have_current_path(confirmation_publish_provider_recruitment_cycle_courses_path(provider_code: provider.provider_code, recruitment_cycle_year:), ignore_query: true) + end + + def and_i_can_not_change_funding_type + expect( + publish_course_confirmation_page.details.funding_type.value.text + ).to eq('Teaching apprenticeship - with salary') + + expect( + publish_course_confirmation_page.details.funding_type.text + ).not_to include('Change') + end + + def and_i_can_not_change_study_mode + expect( + publish_course_confirmation_page.details.study_mode.value.text + ).to eq('Full time') + + expect( + publish_course_confirmation_page.details.study_mode.text + ).not_to include('Change') + end + + def and_i_can_not_change_visa_requirements + expect( + publish_course_confirmation_page.details.skilled_visa_requirements.value.text + ).to eq('No - cannot sponsor') + + expect( + publish_course_confirmation_page.details.skilled_visa_requirements.text + ).not_to include('Change') + end + + def when_i_click_on_add_a_course + click_on 'Add course' + end + + def then_the_tda_course_is_created + expect(course.undergraduate_degree_with_qts?).to be(true) + end + + def and_the_tda_defaults_are_saved + expect(course.program_type).to eq('teacher_degree_apprenticeship') + expect(course.funding).to eq('apprenticeship') + expect(course.can_sponsor_student_visa?).to be false + expect(course.can_sponsor_skilled_worker_visa?).to be false + expect(course.additional_degree_subject_requirements).to be false + expect(course.degree_subject_requirements).to be_nil + expect(course.degree_grade).to eq('not_required') + expect(course.enrichments.last).to be_present + expect(course.enrichments.last.course_length).to eq('4 years') + end + + def and_i_select_no_send + publish_courses_new_level_page.send_fields.is_send_false.click + end + + def then_i_do_not_see_the_change_links_for_study_mode_funding_type_and_visa_sponsorship + within('[data-qa="course__study_mode"]') do + expect(page).to have_no_link('Change') + end + + within('[data-qa="course__funding_type"]') do + expect(page).to have_no_link('Change') + end + + within('[data-qa="course__skilled_worker_visa_sponsorship"]') do + expect(page).to have_no_link('Change') + end + end + + def then_i_do_not_see_the_change_links_for_study_mode_funding_type_and_visa_sponsorship_on_basic_details + within('[data-qa="course__study_mode"]') do + expect(page).to have_no_link('Change') + end + + within('[data-qa="course__funding"]') do + expect(page).to have_no_link('Change') + end + + within('[data-qa="course__can_sponsor_skilled_worker_visa"]') do + expect(page).to have_no_link('Change') + end + end + + def and_i_do_not_see_the_change_link_for_course_length + within('[data-qa="enrichment__course_length"]') do + expect(page).to have_no_link('Change') + end + end + + def when_i_click_on_the_course_i_created + click_on course_name_and_code + when_i_click_on_the_course_basic_details_tab + end + + def when_i_click_on_the_course_basic_details_tab + publish_provider_courses_show_page.basic_details_link.click + end + + def when_i_click_on_the_course_description_tab + publish_provider_courses_show_page.description_link.click + end + + def then_i_do_not_see_the_degree_requirements_row + expect(publish_provider_courses_show_page).not_to have_degree + end + + def given_i_fill_in_all_other_fields_for_the_course + and_i_add_course_details + and_i_add_salary_information + and_i_add_gcse_requirements + end + + def and_i_add_course_details + publish_provider_courses_show_page.about_course.find_link( + text: 'Change details about this course' + ).click + + fill_in 'About this course', with: 'Details about this course' + click_on 'Update about this course' + + publish_provider_courses_show_page.how_school_placements_work.find_link( + text: 'Change details about how placements work' + ).click + + fill_in 'How placements work', with: 'School placements information' + click_on 'Update how placements work' + end + + def and_i_add_salary_information + publish_provider_courses_show_page.salary_details.find_link(text: 'Change salary').click + publish_course_salary_edit_page.salary_details.set('Some salary details') + publish_course_salary_edit_page.submit.click + end + + def and_i_add_gcse_requirements + publish_provider_courses_show_page.gcse.find_link( + text: 'Enter GCSE and equivalency test requirements' + ).click + publish_courses_gcse_requirements_page.pending_gcse_yes_radio.click + publish_courses_gcse_requirements_page.gcse_equivalency_yes_radio.click + publish_courses_gcse_requirements_page.english_equivalency.check + publish_courses_gcse_requirements_page.maths_equivalency.check + publish_courses_gcse_requirements_page.additional_requirements.set('Some Proficiency') + publish_courses_gcse_requirements_page.save.click + end + + def when_i_publish_the_course + publish_provider_courses_show_page.course_button_panel.publish_button.click + end + + def then_the_course_is_published + expect(publish_provider_courses_show_page.errors.map(&:text)).to eq([]) + expect(page).to have_content('Your course has been published.') + expect(course.content_status).to be :published + end + + def provider + @user.providers.first.reload + end + + def course + provider.courses.last + end + + def course_name_and_code + course.decorate.name_and_code + end + + def given_i_am_on_the_check_answers_page_of_a_new_tda_course + given_i_am_authenticated_as_a_school_direct_provider_user + and_i_visit_the_courses_page + and_i_click_on_add_course + and_i_choose_a_secondary_course + and_i_select_a_subject + and_i_choose_an_age_range + and_i_choose_a_degree_awarding_qualification + and_i_choose_the_school + and_i_choose_the_study_site + and_i_choose_the_applications_open_date + and_i_choose_the_first_start_date + then_i_am_on_the_check_your_answers_page + end + + def when_i_visit_the_course_outcome_page + publish_course_confirmation_page.details.outcome.change_link.click + end + + def and_i_choose_qts + publish_courses_outcome_edit_page.qts.choose + and_i_click_continue + end + + def and_i_choose_fee + choose 'Fee - no salary' + and_i_click_continue + end + + def and_i_choose_salaried + choose 'Salary' + and_i_click_continue + end + + def and_i_choose_part_time + uncheck 'Full time' + check 'Part time' + and_i_click_continue + end + + def and_i_choose_to_sponsor_a_student_visa + choose 'Yes' + and_i_click_continue + end + + def and_i_choose_to_sponsor_a_skilled_worker_visa + choose('course_can_sponsor_skilled_worker_visa_true') + and_i_click_continue + end + + def then_i_see_the_correct_attributes_in_the_database_for_fee_paying + course.reload + expect(course.part_time?).to be(true) + expect(course.funding == 'fee').to be(true) + expect(course.can_sponsor_skilled_worker_visa).to be(false) + expect(course.can_sponsor_student_visa).to be(true) + end + + def then_i_see_the_correct_attributes_in_the_database_for_salaried + course.reload + expect(course.study_mode == 'part_time').to be(true) + expect(course.funding == 'salary').to be(true) + expect(course.can_sponsor_skilled_worker_visa).to be(true) + expect(course.can_sponsor_student_visa).to be(false) + end + + def and_the_back_link_points_to_the_confirm_page + expect(URI.parse(find_link('Back')[:href]).path).to eq(confirmation_publish_provider_recruitment_cycle_courses_path( + provider_code: provider.provider_code, + recruitment_cycle_year: + )) + end + + def and_the_back_link_points_to_the_qualification_page + expect(URI.parse(find_link('Back')[:href]).path).to eq(new_publish_provider_recruitment_cycle_courses_outcome_path( + provider_code: provider.provider_code, + recruitment_cycle_year: + )) + end + + def and_the_back_link_points_to_the_funding_type_page + expect(URI.parse(find_link('Back')[:href]).path).to eq(new_publish_provider_recruitment_cycle_courses_funding_type_path( + provider_code: provider.provider_code, + recruitment_cycle_year: + )) + end + + def and_the_back_link_points_to_the_study_mode_page + expect(URI.parse(find_link('Back')[:href]).path).to eq(new_publish_provider_recruitment_cycle_courses_study_mode_path( + provider_code: provider.provider_code, + recruitment_cycle_year: + )) + end + + def when_i_click_back + click_on 'Back' + end + + def then_i_am_on_the_study_mode_page + expect(page).to have_current_path(new_publish_provider_recruitment_cycle_courses_study_mode_path(provider_code: provider.provider_code, recruitment_cycle_year:), ignore_query: true) + end + + def then_i_am_on_the_funding_type_page + expect(page).to have_current_path(new_publish_provider_recruitment_cycle_courses_funding_type_path(provider_code: provider.provider_code, recruitment_cycle_year:), ignore_query: true) + end + + def and_i_add_a_level_requirements + click_on 'Enter A levels and equivalency test requirements' + choose 'Any subject' + and_i_click_continue + choose 'No' + and_i_click_continue + choose 'Yes' + and_i_click_continue + choose 'Yes' + click_on 'Update A levels' + end + + def recruitment_cycle_year + RecruitmentCycle.current.year + end + + alias_method :and_i_do_not_see_the_change_links_for_study_mode_funding_type_and_visa_sponsorship, :then_i_do_not_see_the_change_links_for_study_mode_funding_type_and_visa_sponsorship + alias_method :and_i_visit_the_courses_page, :when_i_visit_the_courses_page + alias_method :and_i_choose_a_degree_awarding_qualification, :when_i_choose_a_degree_awarding_qualification + alias_method :and_i_choose_the_school, :when_i_choose_the_school + alias_method :and_i_choose_the_applications_open_date, :when_i_choose_the_applications_open_date + alias_method :and_i_am_on_the_check_your_answers_page, :then_i_am_on_the_check_your_answers_page + alias_method :when_i_click_continue, :and_i_click_continue +end diff --git a/spec/features/publish/viewing_training_providers_and_their_courses_spec.rb b/spec/features/publish/viewing_training_providers_and_their_courses_spec.rb index 5d55aca33b..39097233dd 100644 --- a/spec/features/publish/viewing_training_providers_and_their_courses_spec.rb +++ b/spec/features/publish/viewing_training_providers_and_their_courses_spec.rb @@ -4,6 +4,7 @@ feature 'Viewing courses as an accredited provider', { can_edit_current_and_next_cycles: false } do before do + allow(Settings.features).to receive(:provider_partnerships).and_return(false) given_i_am_authenticated_as_an_accredited_provider_user and_some_courses_exist_with_one_i_accredit when_i_visit_the_publish_training_provider_index_page diff --git a/spec/features/support/providers/accredited_partners_spec.rb b/spec/features/support/providers/accredited_partners_spec.rb new file mode 100644 index 0000000000..65210ca46b --- /dev/null +++ b/spec/features/support/providers/accredited_partners_spec.rb @@ -0,0 +1,171 @@ +# frozen_string_literal: true + +require 'rails_helper' + +feature 'Accredited provider flow', { can_edit_current_and_next_cycles: false } do + before do + allow(Settings.features).to receive(:provider_partnerships).and_return(true) + given_i_am_authenticated_as_an_admin_user + and_there_are_accredited_providers_in_the_database + and_i_visit_the_index_page + end + + scenario 'i can view the accredited providers tab when there are none' do + then_i_see_the_correct_text_for_no_accredited_providers + end + + scenario 'i can view accredited providers on the index page' do + and_my_provider_has_accrediting_providers + and_i_click_on_the_accredited_provider_tab + then_i_should_see_the_accredited_provider_name_displayed + end + + scenario 'i can edit accredited providers on the index page' do + and_my_provider_has_accrediting_providers + and_i_click_on_the_accredited_provider_tab + and_i_click_change + + when_i_click_the_back_link + then_i_return_to_the_index_page + and_i_click_change + + when_i_input_updated_description + then_i_should_see_the_updated_description + and_i_see_the_success_message + end + + scenario 'i cannot delete accredited providers attached to a course' do + and_my_provider_has_accrediting_providers + and_i_click_on_the_accredited_provider_tab + and_i_click_remove + then_i_should_see_the_cannot_remove_text + end + + scenario 'i can delete accredited providers not attached to a course' do + and_i_click_on_the_accredited_provider_tab + and_i_click_add_accredited_provider + and_i_search_for_an_accredited_provider_with_a_valid_query + and_i_select_the_provider + when_i_input_new_information + and_i_confirm_the_changes + and_i_click_remove + and_i_click_remove_ap + then_i_return_to_the_index_page + and_i_see_the_remove_success_message + end + + private + + def and_i_see_the_remove_success_message + expect(page).to have_content('Accredited partnership removed') + end + + def and_i_see_the_remove_success_message; end + + def and_i_click_remove_ap + click_link_or_button 'Remove accredited partner' + end + + def and_i_confirm_the_changes + click_link_or_button 'Add accredited partner' + end + + def when_i_input_new_information + fill_in 'About the accredited partner', with: 'New AP description' + click_link_or_button 'Continue' + end + + def and_i_select_the_provider + choose @accredited_provider.provider_name + click_link_or_button 'Continue' + end + + def form_title + 'Enter a provider name, UKPRN or postcode' + end + + def and_i_search_for_an_accredited_provider_with_a_valid_query + fill_in form_title, with: @accredited_provider.provider_name + click_link_or_button 'Continue' + end + + def and_i_click_add_accredited_provider + click_link_or_button 'Add accredited partner' + end + + def and_i_click_remove + click_link_or_button 'Remove' + end + + def then_i_should_see_the_cannot_remove_text + expect(page).to have_css('h1', text: 'You cannot remove this accredited provider') + end + + def given_i_am_authenticated_as_an_admin_user + given_i_am_authenticated(user: create(:user, :admin)) + end + + def and_there_are_accredited_providers_in_the_database + @provider = create(:provider, :lead_school) + @accredited_provider = create(:provider, :accredited_provider, provider_name: 'UCL', users: [create(:user)]) + @accredited_provider_two = create(:provider, :accredited_provider, provider_name: 'Accredited provider two') + @accredited_provider_three = create(:provider, :accredited_provider, provider_name: 'Accredited provider three') + end + + def then_i_return_to_the_index_page + expect(page).to have_current_path(support_recruitment_cycle_provider_accredited_partners_path( + recruitment_cycle_year: Settings.current_recruitment_cycle_year, + provider_id: @provider.id + )) + end + + def and_i_visit_the_index_page + visit support_recruitment_cycle_provider_accredited_partners_path( + recruitment_cycle_year: Settings.current_recruitment_cycle_year, + provider_id: @provider.id + ) + end + + def and_i_click_change + click_link_or_button('Change') + end + + def when_i_click_the_back_link + click_link_or_button 'Back' + end + + def and_i_see_the_success_message + expect(page).to have_content('About the accredited provider updated') + end + + def then_i_should_see_the_updated_description + expect(page).to have_text('update the AP description') + end + + def when_i_input_updated_description + fill_in 'About the accredited partner', with: 'update the AP description' + click_link_or_button 'Update description' + end + + def then_i_see_the_correct_text_for_no_accredited_providers + expect(page).to have_text("There are no accredited partnerships for #{@provider.provider_name}") + end + + def and_i_click_on_the_accredited_provider_tab + click_link_or_button 'Accredited partnerships' + end + + def and_my_provider_has_accrediting_providers + course = build(:course, accrediting_provider: build(:provider, :accredited_provider, provider_name: 'Accrediting provider name')) + + @provider.accredited_partnerships.create(accredited_provider: course.accrediting_provider, description: 'Description') + @provider.courses << course + end + + def then_i_should_see_the_accredited_provider_name_displayed + expect(page).to have_css( + 'h2.govuk-summary-card__title a.govuk-link', + text: 'Accrediting provider name' + ) + end +end diff --git a/spec/features/support/providers/accredited_provider_search/searching_for_an_accredited_provider_spec.rb b/spec/features/support/providers/accredited_provider_search/searching_for_an_accredited_provider_enrichments_spec.rb similarity index 97% rename from spec/features/support/providers/accredited_provider_search/searching_for_an_accredited_provider_spec.rb rename to spec/features/support/providers/accredited_provider_search/searching_for_an_accredited_provider_enrichments_spec.rb index 879f8198fc..0d825e29ff 100644 --- a/spec/features/support/providers/accredited_provider_search/searching_for_an_accredited_provider_spec.rb +++ b/spec/features/support/providers/accredited_provider_search/searching_for_an_accredited_provider_enrichments_spec.rb @@ -2,8 +2,9 @@ require 'rails_helper' -feature 'Searching for an accredited provider' do +feature 'Searching for an accredited provider enrichments' do before do + allow(Settings.features).to receive(:provider_partnerships).and_return(false) given_i_am_authenticated_as_an_admin_user and_there_are_accredited_providers_in_the_database end diff --git a/spec/features/support/providers/accredited_provider_search/searching_for_an_accredited_provider_partnerships_spec.rb b/spec/features/support/providers/accredited_provider_search/searching_for_an_accredited_provider_partnerships_spec.rb new file mode 100644 index 0000000000..87e0a0863c --- /dev/null +++ b/spec/features/support/providers/accredited_provider_search/searching_for_an_accredited_provider_partnerships_spec.rb @@ -0,0 +1,191 @@ +# frozen_string_literal: true + +require 'rails_helper' + +feature 'Searching for an accredited provider' do + before do + allow(Settings.features).to receive(:provider_partnerships).and_return(true) + given_i_am_authenticated_as_an_admin_user + and_there_are_accredited_providers_in_the_database + end + + scenario 'i can search for an accredited provider by query' do + when_i_visit_the_accredited_provider_search_page + and_i_search_with_an_invalid_query + then_i_should_see_an_error_message + + when_i_search_for_an_accredited_provider_with_a_valid_query + then_i_see_the_provider_i_searched_for + + when_i_continue_without_selecting_an_accredited_provider + then_i_should_see_an_error_message('Select an accredited provider') + and_i_should_still_see_the_provider_i_searched_for + + when_i_select_the_provider + and_i_continue_without_entering_a_description + then_i_should_see_an_error_message('Enter details about the accredited partnership') + + when_i_enter_a_description + and_i_confirm_the_changes + then_i_should_be_taken_to_the_index_page + and_i_should_see_a_success_message + and_i_should_see_the_accredited_providers + end + + scenario 'back links behaviour' do + when_i_am_on_the_confirm_page + and_i_click_the_change_link_for('accredited partner name') + then_i_should_be_taken_to_the_accredited_provider_search_page + when_i_click_the_back_link + then_i_should_be_taken_back_to_the_confirm_page + + when_i_am_on_the_confirm_page + and_i_click_the_change_link_for('accredited partner description') + then_i_should_be_taken_to_the_accredited_provider_description_page + when_i_click_the_back_link + then_i_should_be_taken_back_to_the_confirm_page + end + + private + + def given_i_am_authenticated_as_an_admin_user + given_i_am_authenticated(user: create(:user, :admin)) + end + + def and_there_are_accredited_providers_in_the_database + @accredited_provider = create(:provider, :accredited_provider, provider_name: 'UCL', users: [create(:user)]) + @accredited_provider_two = create(:provider, :accredited_provider, provider_name: 'Accredited provider two') + @accredited_provider_three = create(:provider, :accredited_provider, provider_name: 'Accredited provider three') + end + + def when_i_visit_the_accredited_provider_search_page + visit search_support_recruitment_cycle_provider_accredited_providers_path( + recruitment_cycle_year: Settings.current_recruitment_cycle_year, + provider_id: provider.id + ) + end + + def when_i_search_for_an_accredited_provider_with_a_valid_query + fill_in form_title, with: @accredited_provider.provider_name + click_continue + end + + def then_i_see_the_provider_i_searched_for + expect(page).to have_content(@accredited_provider.provider_name) + expect(page).to have_no_content(@accredited_provider_two.provider_name) + expect(page).to have_no_content(@accredited_provider_three.provider_name) + end + + def when_i_select_the_provider + choose @accredited_provider.provider_name + click_continue + end + + def then_i_should_be_taken_to_the_index_page + expect(page).to have_current_path( + support_recruitment_cycle_provider_accredited_partners_path( + recruitment_cycle_year: Settings.current_recruitment_cycle_year, + provider_id: provider.id + ) + ) + end + + def and_i_search_with_an_invalid_query + fill_in form_title, with: '' + click_continue + end + + def then_i_should_see_an_error_message(error_message = form_title) + expect(page).to have_content(error_message) + end + + def when_i_continue_without_selecting_an_accredited_provider + click_continue + end + + def and_i_should_still_see_the_provider_i_searched_for + expect(page).to have_content(@accredited_provider.provider_name) + expect(page).to have_no_content(@accredited_provider_two.provider_name) + expect(page).to have_no_content(@accredited_provider_three.provider_name) + end + + def when_i_enter_a_description + fill_in 'About the accredited partner', with: 'This is a description' + click_continue + end + + def and_i_confirm_the_changes + expect do + click_link_or_button 'Add accredited partner' + end.to have_enqueued_email(Users::OrganisationMailer, :added_as_an_organisation_to_training_partner) + end + + def and_i_should_see_a_success_message + expect(page).to have_content('Accredited partner added') + end + + def and_i_should_see_the_accredited_providers + expect(page).to have_css('.govuk-summary-card', count: 1) + expect(page).to have_content(@accredited_provider.provider_name) + end + + def click_continue + click_link_or_button 'Continue' + end + + def when_i_am_on_the_confirm_page + when_i_visit_the_accredited_provider_search_page + when_i_search_for_an_accredited_provider_with_a_valid_query + when_i_select_the_provider + when_i_enter_a_description + end + + def and_i_click_the_change_link_for(field) + within '.govuk-summary-list' do + click_link_or_button "Change #{field}" + end + end + + def then_i_should_be_taken_to_the_accredited_provider_search_page + expect(page).to have_current_path( + search_support_recruitment_cycle_provider_accredited_providers_path( + recruitment_cycle_year: Settings.current_recruitment_cycle_year, + provider_id: provider.id, + goto_confirmation: true + ) + ) + end + + def then_i_should_be_taken_to_the_accredited_provider_description_page + expect(page).to have_current_path( + new_support_recruitment_cycle_provider_accredited_partner_path( + recruitment_cycle_year: Settings.current_recruitment_cycle_year, + provider_id: provider.id, + goto_confirmation: true + ) + ) + end + + def when_i_click_the_back_link + click_link_or_button 'Back' + end + + def then_i_should_be_taken_back_to_the_confirm_page + expect(page).to have_current_path( + check_support_recruitment_cycle_provider_accredited_partners_path( + recruitment_cycle_year: Settings.current_recruitment_cycle_year, + provider_id: provider.id + ) + ) + end + + def provider + @provider ||= create(:provider) + end + + def form_title + 'Enter a provider name, UKPRN or postcode' + end + + alias_method :and_i_continue_without_entering_a_description, :click_continue +end diff --git a/spec/features/support/providers/accredited_providers_spec.rb b/spec/features/support/providers/accredited_providers_spec.rb index f83f5a008a..e70be9a306 100644 --- a/spec/features/support/providers/accredited_providers_spec.rb +++ b/spec/features/support/providers/accredited_providers_spec.rb @@ -4,6 +4,7 @@ feature 'Accredited provider flow', { can_edit_current_and_next_cycles: false } do before do + allow(Settings.features).to receive(:provider_partnerships).and_return(false) given_i_am_authenticated_as_an_admin_user and_there_are_accredited_providers_in_the_database and_i_visit_the_index_page diff --git a/spec/features/view_components_enrichments_spec.rb b/spec/features/view_components_enrichments_spec.rb new file mode 100644 index 0000000000..9c32a67db9 --- /dev/null +++ b/spec/features/view_components_enrichments_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.feature 'view components' do + before do + allow(Settings.features).to receive(:provider_partnerships).and_return(false) + end + + all_links = (ViewComponent::Preview.all.map do |component| + component.examples.map do |example| + "#{Rails.application.config.view_component.preview_route}/#{component.preview_name}/#{example}" + end + end).flatten + + shared_examples 'navigate to' do |link| + scenario "navigate to #{link}" do + visit link + + expect(page.status_code).to eq(200) + expect(page).to have_css('#main-content') + end + end + + all_links.each do |link| + include_examples 'navigate to', link + end +end diff --git a/spec/features/view_components_spec.rb b/spec/features/view_components_spec.rb index 92b7c01e5a..4f5420c92f 100644 --- a/spec/features/view_components_spec.rb +++ b/spec/features/view_components_spec.rb @@ -3,6 +3,10 @@ require 'rails_helper' RSpec.feature 'view components' do + before do + allow(Settings.features).to receive(:provider_partnerships).and_return(true) + end + all_links = (ViewComponent::Preview.all.map do |component| component.examples.map do |example| "#{Rails.application.config.view_component.preview_route}/#{component.preview_name}/#{example}" diff --git a/spec/forms/provider_partnership_form_spec.rb b/spec/forms/provider_partnership_form_spec.rb new file mode 100644 index 0000000000..c4f2f4c75f --- /dev/null +++ b/spec/forms/provider_partnership_form_spec.rb @@ -0,0 +1,120 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe ProviderPartnershipForm, type: :model do + subject { described_class.new(user, model) } + + let(:user) { create(:user) } + let(:provider) { create(:provider) } + let(:model) { create(:provider_partnership, training_provider: provider) } + + describe 'validations' do + it { is_expected.to validate_presence_of(:description) } + + context 'word count' do + before do + subject.description = Faker::Lorem.sentence(word_count: 251) + subject.valid? + end + + it 'validates the word count for the description' do + expect(subject).not_to be_valid + expect(subject.errors[:description]) + .to include(I18n.t('activemodel.errors.models.provider_partnership_form.attributes.description.too_long')) + end + end + end + + describe '#stash' do + subject { described_class.new(user, model, params:).stash } + + let(:accredited_provider) { create(:provider, :accredited_provider) } + let(:params) do + { + accredited_provider_id: accredited_provider.id, + description: 'Foo' + } + end + + it { is_expected.to be_truthy } + end + + describe '#accredited_provider' do + subject { described_class.new(user, model, params:).accredited_provider } + + let(:recruitment_cycle) { find_or_create(:recruitment_cycle) } + let(:next_recruitment_cycle) { create(:recruitment_cycle, :next) } + let(:model) { create(:provider_partnership) } + let(:accredited_provider) { create(:provider, :accredited_provider) } + let(:params) do + { + accredited_provider_id: accredited_provider.id, + description: 'Foo' + } + end + + it 'returns the accredited provider' do + expect(subject).to eq(accredited_provider) + end + + context 'when accredited provider is in the next recruitment cycle' do + let(:accredited_provider_in_next_cycle) { create(:provider, :accredited_provider, recruitment_cycle: next_recruitment_cycle) } + let(:params) do + { + accredited_provider_id: accredited_provider_in_next_cycle.id, + description: 'Foo' + } + end + + before do + allow(RecruitmentCycle).to receive(:current).and_return(next_recruitment_cycle) + end + + it 'returns the accredited provider from the next cycle' do + expect(subject).to eq(accredited_provider_in_next_cycle) + end + end + end + + describe '#save!' do + subject { described_class.new(user, model, params:) } + + let(:accredited_provider) { create(:provider, :accredited_provider, users: [create(:user)]) } + let(:params) do + { + accredited_provider_id: accredited_provider.id, + description: 'Foo' + } + end + + context 'when no partnership exists' do + it 'correctly sets the enrichment structure' do + expect { subject.save! } + .to change(model, :description).to(params[:description]) + end + end + + context 'when provider has existing accredited provider enrichments' do + let(:accredited_provider) { create(:accredited_provider) } + let(:model) { create(:provider_partnership, training_provider: provider, accredited_provider:, description: 'Existing') } + + it 'updates the provider with the new accredited provider information' do + subject.save! + + expect(model.accredited_provider.provider_code).to eq(accredited_provider.provider_code) + expect(model.description).to eq('Foo') + end + end + + it 'sends a notification email to the accredited provider users' do + expect(Users::OrganisationMailer).to receive(:added_as_an_organisation_to_training_partner).with( + recipient: accredited_provider.users.first, + provider: model, + accredited_provider: + ).and_call_original + + subject.save! + end + end +end diff --git a/spec/helpers/navigation_bar_helper_spec.rb b/spec/helpers/navigation_bar_helper_spec.rb index aa3f8dcbe7..0f50220360 100644 --- a/spec/helpers/navigation_bar_helper_spec.rb +++ b/spec/helpers/navigation_bar_helper_spec.rb @@ -8,25 +8,55 @@ helper.navigation_items(provider) end - let(:accredited_provider_item) { subject.find { |item| item[:name] == 'Accredited providers' } } + context 'when Settings.features.provider_partnerships is false' do + before { allow(Settings.features).to receive(:provider_partnerships).and_return(false) } - context 'when provider is an accredited provider' do - let(:provider) { create(:provider, :accredited_provider) } + let(:accredited_provider_item) { subject.find { |item| item[:name] == 'Accredited providers' } } - it 'does not include accredited_provider in items' do - expect(accredited_provider_item).to be_nil + context 'when provider is an accredited provider' do + let(:provider) { create(:provider, :accredited_provider) } + + it 'does not include accredited_provider in items' do + expect(accredited_provider_item).to be_nil + end + end + + context 'when provider is not an accredited provider' do + let(:provider) { create(:provider) } + + it 'includes accredited_provider in items' do + expect(accredited_provider_item).not_to be_nil + end + + it 'includes the correct link to accredited providers' do + expect(accredited_provider_item[:url]).to eq publish_provider_recruitment_cycle_accredited_providers_path(provider.provider_code, provider.recruitment_cycle.year) + end end end - context 'when provider is not an accredited provider' do - let(:provider) { create(:provider) } + context 'when Settings.features.provider_partnerships is true' do + before { allow(Settings.features).to receive(:provider_partnerships).and_return(true) } - it 'includes accredited_provider in items' do - expect(accredited_provider_item).not_to be_nil + let(:accredited_provider_item) { subject.find { |item| item[:name] == 'Accredited partnerships' } } + + context 'when provider is an accredited provider' do + let(:provider) { create(:provider, :accredited_provider) } + + it 'does not include accredited_provider in items' do + expect(accredited_provider_item).to be_nil + end end - it 'includes the correct link to accredited providers' do - expect(accredited_provider_item[:url]).to eq publish_provider_recruitment_cycle_accredited_providers_path(provider.provider_code, provider.recruitment_cycle.year) + context 'when provider is not an accredited provider' do + let(:provider) { create(:provider) } + + it 'includes accredited_provider in items' do + expect(accredited_provider_item).not_to be_nil + end + + it 'includes the correct link to accredited providers' do + expect(accredited_provider_item[:url]).to eq publish_provider_recruitment_cycle_accredited_partnerships_path(provider.provider_code, provider.recruitment_cycle.year) + end end end end diff --git a/spec/helpers/view_helper_spec.rb b/spec/helpers/view_helper_spec.rb index ed8d78b64a..5dc2291f85 100644 --- a/spec/helpers/view_helper_spec.rb +++ b/spec/helpers/view_helper_spec.rb @@ -68,7 +68,7 @@ def preview?(_) = true it 'returns the publish accrediting provider url' do expect(x_accrediting_provider_url).to eq( - accredited_by_publish_provider_recruitment_cycle_course_path( + ratified_by_publish_provider_recruitment_cycle_course_path( course.provider_code, course.recruitment_cycle_year, course.course_code diff --git a/spec/lib/constraints/partnership_feature_spec.rb b/spec/lib/constraints/partnership_feature_spec.rb new file mode 100644 index 0000000000..cc27a6dcdf --- /dev/null +++ b/spec/lib/constraints/partnership_feature_spec.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +require 'rails_helper' + +module Constraints + RSpec.describe PartnershipFeature do + describe 'when the feature is on' do + before do + allow(Settings.features).to receive(:provider_partnerships).and_return(true) + end + + context 'when we pass :on' do + let(:constraint) { described_class.new(:on) } + + it 'matches' do + expect(constraint.matches?(nil)).to be_truthy + end + end + + context 'when we pass :off' do + let(:constraint) { described_class.new(:off) } + + it 'does not match' do + expect(constraint.matches?(nil)).to be_falsey + end + end + end + + describe 'when the feature is off' do + before do + allow(Settings.features).to receive(:provider_partnerships).and_return(false) + end + + context 'when we pass :on' do + let(:constraint) { described_class.new(:on) } + + it 'does not match' do + expect(constraint.matches?(nil)).to be_falsey + end + end + + context 'when we pass :off' do + let(:constraint) { described_class.new(:off) } + + it 'matches' do + expect(constraint.matches?(nil)).to be_truthy + end + end + end + end +end diff --git a/spec/models/course_spec.rb b/spec/models/course_spec.rb index cf95fbf3b9..f9ec47a734 100644 --- a/spec/models/course_spec.rb +++ b/spec/models/course_spec.rb @@ -2287,6 +2287,33 @@ end end + describe '#ratifying_provider_description' do + subject { course.ratifying_provider_description } + + context 'for courses without ratifying provider' do + let(:accrediting_provider) { nil } + let(:course) { create(:course, accrediting_provider:) } + + it { is_expected.to be_nil } + end + + context 'for courses with ratifying provider' do + let(:provider) { create(:provider) } + let(:accrediting_provider) { build(:accredited_provider) } + let(:course) { create(:course, provider:, accrediting_provider:) } + + context 'without any provider partnership' do + it { is_expected.to be_nil } + end + + context 'with accrediting_provider_enrichments' do + let(:provider) { create(:provider, accredited_partnerships: [build(:provider_partnership, accredited_provider: accrediting_provider, description: 'one two three')]) } + + it { is_expected.to match 'one two three' } + end + end + end + describe '#accrediting_provider_description' do subject { course.accrediting_provider_description } diff --git a/spec/models/provider/accredited_providers_enrichments_spec.rb b/spec/models/provider/accredited_providers_enrichments_spec.rb new file mode 100644 index 0000000000..bc2f2b64cf --- /dev/null +++ b/spec/models/provider/accredited_providers_enrichments_spec.rb @@ -0,0 +1,91 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Provider do + subject do + provider.accredited_bodies + end + + before do + allow(Settings.features).to receive(:provider_partnerships).and_return(false) + provider.reload + end + + let(:accrediting_provider_enrichments) { [] } + let(:description) { 'Ye olde establishmente' } + let(:courses) { [] } + let(:provider) do + create(:provider, + provider_name: 'ACME SCITT', + provider_code: 'A01', + accrediting_provider_enrichments:, + courses:) + end + + context 'with no accrediting provider (via courses)' do + it { is_expected.to be_empty } + + context 'with an old accredited provider enrichment' do + let(:accrediting_provider_enrichments) do + [{ + 'Description' => description, + # XX4 might have previously been an accrediting provider for this provider, and the data is still in the database + 'UcasProviderCode' => 'XX4' + }] + end + + it { is_expected.to be_empty } + end + end + + context 'with an accrediting provider (via courses)' do + let(:accrediting_provider) { build(:provider, provider_code: 'AP1') } + let(:courses) { [build(:course, course_code: 'P33P', accrediting_provider:)] } + let(:accredited_provider) { accrediting_provider } + + let(:accrediting_provider_enrichments) do + [{ UcasProviderCode: accredited_provider.provider_code }] + end + + its(:length) { is_expected.to be(1) } + + describe 'the returned accredited provider' do + subject { provider.accredited_bodies.first } + + its([:description]) { is_expected.to eq('') } + its([:provider_code]) { is_expected.to eq(accrediting_provider.provider_code) } + its([:provider_name]) { is_expected.to eq(accrediting_provider.provider_name) } + end + + context 'with an accredited provider enrichment' do + let(:accrediting_provider_enrichments) do + [{ + 'Description' => description, + 'UcasProviderCode' => accrediting_provider.provider_code + }] + end + + its(:length) { is_expected.to be(1) } + + describe 'the returned accredited provider' do + subject { provider.accredited_bodies.first } + + its([:description]) { is_expected.to eq(description) } + its([:provider_code]) { is_expected.to eq(accrediting_provider.provider_code) } + its([:provider_name]) { is_expected.to eq(accrediting_provider.provider_name) } + end + end + + context 'with a corrupt accredited provider enrichment' do + let(:accrediting_provider_enrichments) do + [{ + 'Description' => description + # UcasProviderCode missing. We found data like this in our database so need to handle it. + }] + end + + its(:length) { is_expected.to be(0) } + end + end +end diff --git a/spec/models/provider/accredited_providers_spec.rb b/spec/models/provider/accredited_providers_spec.rb deleted file mode 100644 index 650a6b51f5..0000000000 --- a/spec/models/provider/accredited_providers_spec.rb +++ /dev/null @@ -1,96 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Provider do - let(:accrediting_provider_enrichments) { [] } - let(:courses) { [] } - let(:provider) do - create(:provider, - provider_name: 'ACME SCITT', - provider_code: 'A01', - accrediting_provider_enrichments:, - courses:) - end - - before do - # NOTE: provider needs to be reloaded due to - # provider.accrediting_providers - # provider.accredited_bodies - provider.reload - end - - describe '#accredited_bodies' do - subject do - provider.accredited_bodies - end - - let(:description) { 'Ye olde establishmente' } - - context 'with no accrediting provider (via courses)' do - it { is_expected.to be_empty } - - context 'with an old accredited provider enrichment' do - let(:accrediting_provider_enrichments) do - [{ - 'Description' => description, - # XX4 might have previously been an accrediting provider for this provider, and the data is still in the database - 'UcasProviderCode' => 'XX4' - }] - end - - it { is_expected.to be_empty } - end - end - - context 'with an accrediting provider (via courses)' do - let(:accrediting_provider) { build(:provider, provider_code: 'AP1') } - let(:courses) { [build(:course, course_code: 'P33P', accrediting_provider:)] } - let(:accredited_provider) { accrediting_provider } - - let(:accrediting_provider_enrichments) do - [{ UcasProviderCode: accredited_provider.provider_code }] - end - - its(:length) { is_expected.to be(1) } - - describe 'the returned accredited provider' do - subject { provider.accredited_bodies.first } - - its([:description]) { is_expected.to eq('') } - its([:provider_code]) { is_expected.to eq(accrediting_provider.provider_code) } - its([:provider_name]) { is_expected.to eq(accrediting_provider.provider_name) } - end - - context 'with an accredited provider enrichment' do - let(:accrediting_provider_enrichments) do - [{ - 'Description' => description, - 'UcasProviderCode' => accrediting_provider.provider_code - }] - end - - its(:length) { is_expected.to be(1) } - - describe 'the returned accredited provider' do - subject { provider.accredited_bodies.first } - - its([:description]) { is_expected.to eq(description) } - its([:provider_code]) { is_expected.to eq(accrediting_provider.provider_code) } - its([:provider_name]) { is_expected.to eq(accrediting_provider.provider_name) } - end - end - - context 'with a corrupt accredited provider enrichment' do - let(:accrediting_provider_enrichments) do - [{ - 'Description' => description - # UcasProviderCode missing. We found data like this in our database so need to handle it. - }] - end - - its(:length) { is_expected.to be(0) } - end - end - end -end diff --git a/spec/models/provider/validation_enrichments_spec.rb b/spec/models/provider/validation_enrichments_spec.rb new file mode 100644 index 0000000000..e469e82878 --- /dev/null +++ b/spec/models/provider/validation_enrichments_spec.rb @@ -0,0 +1,211 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'validation' do + let(:accrediting_provider_enrichments) { [] } + let(:courses) { [] } + let(:provider) do + create(:provider, + provider_name: 'ACME SCITT', + provider_code: 'A01', + accrediting_provider_enrichments:, + courses:) + end + + describe 'update' do + let(:provider) { build(:provider) } + + describe 'email' do + it 'validates email is present' do + provider.email = '' + provider.valid? :update + + expect(provider.errors[:email]).to include('Enter an email address in the correct format, like name@example.com') + end + + it 'validates email contains an @ symbol' do + provider.email = 'meow' + provider.valid? :update + + expect(provider.errors[:email]).to include('Enter an email address in the correct format, like name@example.com') + end + + it 'Does not validate the email if it is not present' do + provider.website = 'cats4lyf.cat' + + expect(provider.valid?(:update)).to be true + end + end + + describe 'telephone' do + it 'validates telephone is present' do + provider.telephone = '' + provider.valid? :update + + expect(provider.errors[:telephone]).to include('Enter a telephone number') + end + + it 'Correctly validates valid phone numbers' do + provider.telephone = '+447 123 123 123' + expect(provider.valid?(:update)).to be true + end + + it 'Correctly invalidates invalid phone numbers' do + provider.telephone = '123cat456' + expect(provider.valid?(:update)).to be false + expect(provider.errors[:telephone]).to include('Enter a telephone number, like 01632 960 001, 07700 900 982 or +44 0808 157 0192') + end + + it 'Correctly invalidates short phone numbers' do + provider.telephone = '1234567' + expect(provider.valid?(:update)).to be false + expect(provider.errors[:telephone]).to include('Telephone number must contain 8 numbers or more') + end + + it 'Correctly invalidates long phone numbers' do + provider.telephone = '123456791123456789' + expect(provider.valid?(:update)).to be false + expect(provider.errors[:telephone]).to include('Telephone number must contain 15 numbers or fewer') + end + + it 'Does not validate the telephone if it is not present' do + provider.website = 'cats4lyf.cat' + + expect(provider.valid?(:update)).to be true + end + end + end + + describe 'on update' do + context 'setting field to nil' do + subject { provider } + + it { is_expected.to validate_presence_of(:train_with_us).on(:update) } + it { is_expected.to validate_presence_of(:train_with_disability).on(:update) } + end + end + + describe '#train_with_us' do + subject { build(:provider, train_with_us:) } + + let(:word_count) { 250 } + let(:train_with_us) { Faker::Lorem.sentence(word_count:) } + + context 'word count within limit' do + it { is_expected.to be_valid } + end + + context 'word count exceed limit' do + let(:word_count) { 250 + 1 } + + it { is_expected.not_to be_valid } + end + end + + describe '#train_with_disability' do + subject { build(:provider, train_with_disability:) } + + let(:word_count) { 250 } + let(:train_with_disability) { Faker::Lorem.sentence(word_count:) } + + context 'word count within limit' do + it { is_expected.to be_valid } + end + + context 'word count exceed limit' do + let(:word_count) { 250 + 1 } + + it { is_expected.not_to be_valid } + end + end + + context 'no accrediting_providers' do + describe '#accrediting_provider_providers' do + subject do + provider.accrediting_provider_enrichments = accrediting_provider_enrichments + provider + end + + let(:word_count) { 100 } + + let(:accrediting_provider_enrichments) do + result = [] + 10.times do |index| + result << + { + 'Description' => Faker::Lorem.sentence(word_count:), + 'UcasProviderCode' => "UPC#{index}" + } + end + result + end + + let(:provider) do + create(:provider) + end + + context 'word count within limit' do + it { is_expected.to be_valid } + end + + context 'word count exceed limit' do + let(:word_count) { 100 + 1 } + # NOTE: its valid as it is orphaned data + # ie a previous course + # with an acrediting provider was removed + # but the accrediting provider enrichment was left behind + + it { is_expected.to be_valid } + end + end + end + + context 'with accrediting_providers' do + describe '#accrediting_provider_providers' do + subject do + provider.accrediting_provider_enrichments = accrediting_provider_enrichments + provider + end + + let(:word_count) { 100 } + + let(:accrediting_providers) do + result = [] + 10.times do + result << create(:provider) + end + result + end + + let(:accrediting_provider_enrichments) do + accrediting_providers.map do |ap| + { + 'Description' => Faker::Lorem.sentence(word_count:), + 'UcasProviderCode' => ap.provider_code.to_s + } + end + end + + let(:courses) do + accrediting_providers.map do |ap| + build(:course, accrediting_provider: ap) + end + end + + let(:provider) do + create(:provider, courses:) + end + + context 'word count within limit' do + it { is_expected.to be_valid } + end + + context 'word count exceed limit' do + let(:word_count) { 100 + 1 } + + it { is_expected.not_to be_valid } + end + end + end +end diff --git a/spec/models/provider/validation_spec.rb b/spec/models/provider/validation_spec.rb index e469e82878..1adab16f91 100644 --- a/spec/models/provider/validation_spec.rb +++ b/spec/models/provider/validation_spec.rb @@ -9,7 +9,6 @@ create(:provider, provider_name: 'ACME SCITT', provider_code: 'A01', - accrediting_provider_enrichments:, courses:) end @@ -119,93 +118,4 @@ it { is_expected.not_to be_valid } end end - - context 'no accrediting_providers' do - describe '#accrediting_provider_providers' do - subject do - provider.accrediting_provider_enrichments = accrediting_provider_enrichments - provider - end - - let(:word_count) { 100 } - - let(:accrediting_provider_enrichments) do - result = [] - 10.times do |index| - result << - { - 'Description' => Faker::Lorem.sentence(word_count:), - 'UcasProviderCode' => "UPC#{index}" - } - end - result - end - - let(:provider) do - create(:provider) - end - - context 'word count within limit' do - it { is_expected.to be_valid } - end - - context 'word count exceed limit' do - let(:word_count) { 100 + 1 } - # NOTE: its valid as it is orphaned data - # ie a previous course - # with an acrediting provider was removed - # but the accrediting provider enrichment was left behind - - it { is_expected.to be_valid } - end - end - end - - context 'with accrediting_providers' do - describe '#accrediting_provider_providers' do - subject do - provider.accrediting_provider_enrichments = accrediting_provider_enrichments - provider - end - - let(:word_count) { 100 } - - let(:accrediting_providers) do - result = [] - 10.times do - result << create(:provider) - end - result - end - - let(:accrediting_provider_enrichments) do - accrediting_providers.map do |ap| - { - 'Description' => Faker::Lorem.sentence(word_count:), - 'UcasProviderCode' => ap.provider_code.to_s - } - end - end - - let(:courses) do - accrediting_providers.map do |ap| - build(:course, accrediting_provider: ap) - end - end - - let(:provider) do - create(:provider, courses:) - end - - context 'word count within limit' do - it { is_expected.to be_valid } - end - - context 'word count exceed limit' do - let(:word_count) { 100 + 1 } - - it { is_expected.not_to be_valid } - end - end - end end diff --git a/spec/models/provider_partnership_spec.rb b/spec/models/provider_partnership_spec.rb index bdcb065b16..4ed7b8b2b2 100644 --- a/spec/models/provider_partnership_spec.rb +++ b/spec/models/provider_partnership_spec.rb @@ -17,6 +17,22 @@ describe 'validations' do before { subject.validate } + describe '#description must be present' do + subject(:partnership) { build(:provider_partnership, description: '') } + + it 'has correct error message' do + expect(subject.errors.messages[:description]).to include('Enter details about the accredited partnership') + end + end + + describe '#description length' do + subject(:partnership) { build(:provider_partnership, description: Faker::Lorem.sentence(word_count: 101)) } + + it 'has correct error message' do + expect(subject.errors.messages[:description]).to include('Description about the accredited provider must be 100 words or fewer') + end + end + context 'blank accredited provider' do subject(:partnership) { build(:provider_partnership, accredited_provider: nil) } diff --git a/spec/policies/provider_policy_accredited_enrichments_spec.rb b/spec/policies/provider_policy_accredited_enrichments_spec.rb new file mode 100644 index 0000000000..302c7336a1 --- /dev/null +++ b/spec/policies/provider_policy_accredited_enrichments_spec.rb @@ -0,0 +1,82 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'ProviderPolicyAccreditedEnrichments' do + subject { ProviderPolicy } + + before do + allow(Settings.features).to receive(:provider_partnerships).and_return(false) + end + + let(:user) { build(:user) } + let(:admin) { build(:user, :admin) } + + describe 'scope' do + it 'limits the providers to those the user is assigned to' do + provider1 = create(:provider, users: [user]) + _provider2 = create(:provider) + + expect(Pundit.policy_scope(user, Provider.all)).to eq [provider1] + end + end + + permissions :index?, :suggest?, :new? do + it { is_expected.to permit user } + end + + permissions :create? do + let(:user_outside_org) { build(:user) } + let(:provider) { build(:provider, users: [user]) } + + it { is_expected.not_to permit(user, provider) } + it { is_expected.not_to permit(user_outside_org, provider) } + it { is_expected.to permit(admin, provider) } + end + + permissions :can_show_training_provider? do + let(:accrediting_provider_enrichments) { [{ UcasProviderCode: course.accredited_provider_code }] } + + let(:allowed_user) { create(:user, providers: [provider]) } + let(:not_allowed_user) { create(:user) } + + let(:course) { create(:course, :with_accrediting_provider) } + + let(:provider) { course.accrediting_provider } + let(:training_provider) do + course.provider + course.provider.accrediting_provider_enrichments = accrediting_provider_enrichments + course.provider + end + + it { is_expected.to permit(admin, training_provider) } + it { is_expected.to permit(allowed_user, training_provider) } + it { is_expected.not_to permit(not_allowed_user, training_provider) } + end + + describe '#permitted_provider_attributes' do + context 'when user' do + subject { ProviderPolicy.new(user, build(:provider)) } + + it 'includes email' do + expect(subject.permitted_provider_attributes).to include(:email) + end + + it 'excludes provider_name' do + expect(subject.permitted_provider_attributes).not_to include(:provider_name) + end + end + + context 'when admin' do + subject { ProviderPolicy.new(admin, build(:provider)) } + + it 'includes email' do + expect(subject.permitted_provider_attributes).to include(:email) + end + + it 'includes provider_name' do + expect(subject.permitted_provider_attributes).to include(:provider_name) + end + end + end +end diff --git a/spec/policies/provider_policy_spec.rb b/spec/policies/provider_policy_spec.rb index 9fa3d37bc5..6071ee80bb 100644 --- a/spec/policies/provider_policy_spec.rb +++ b/spec/policies/provider_policy_spec.rb @@ -5,6 +5,10 @@ describe ProviderPolicy do subject { described_class } + before do + allow(Settings.features).to receive(:provider_partnerships).and_return(true) + end + let(:user) { build(:user) } let(:admin) { build(:user, :admin) } @@ -31,8 +35,6 @@ end permissions :can_show_training_provider? do - let(:accrediting_provider_enrichments) { [{ UcasProviderCode: course.accredited_provider_code }] } - let(:allowed_user) { create(:user, providers: [provider]) } let(:not_allowed_user) { create(:user) } @@ -40,9 +42,9 @@ let(:provider) { course.accrediting_provider } let(:training_provider) do - course.provider - course.provider.accrediting_provider_enrichments = accrediting_provider_enrichments - course.provider + course.provider.tap do |p| + p.accredited_partnerships.create(accredited_provider: course.accrediting_provider, description: 'asdfa') + end end it { is_expected.to permit(admin, training_provider) } diff --git a/spec/serializers/api/public/v1/serializable_course_spec.rb b/spec/serializers/api/public/v1/serializable_course_spec.rb index b42d36a073..4e2060eacf 100644 --- a/spec/serializers/api/public/v1/serializable_course_spec.rb +++ b/spec/serializers/api/public/v1/serializable_course_spec.rb @@ -17,12 +17,22 @@ context 'when there is an accredited body with enrichments' do before do + allow(Settings.features).to receive(:provider_partnerships).and_return(false) course.provider.update(accrediting_provider_enrichments: [{ Description: 'foo', UcasProviderCode: course.accrediting_provider.provider_code }]) end it { is_expected.to have_attribute(:about_accredited_body).with_value(course.provider.accrediting_provider_enrichments.first.Description) } end + context 'when there is a ratifying provider with description' do + before do + allow(Settings.features).to receive(:provider_partnerships).and_return(true) + course.provider.accredited_partnerships.create(description: 'foo', accredited_provider: course.accrediting_provider) + end + + it { is_expected.to have_attribute(:about_accredited_body).with_value(course.provider.accredited_partnerships.find_by(accredited_provider_id: course.accrediting_provider).description) } + end + it { is_expected.to have_attribute(:about_accredited_body).with_value(nil) } it { is_expected.to have_attribute(:about_course).with_value(course.latest_published_enrichment.about_course) } it { is_expected.to have_attribute(:accredited_body_code).with_value(course.accredited_provider_code) } diff --git a/spec/services/stores/user_store_spec.rb b/spec/services/stores/user_store_spec.rb index 9413827c5a..e7f569b446 100644 --- a/spec/services/stores/user_store_spec.rb +++ b/spec/services/stores/user_store_spec.rb @@ -6,6 +6,6 @@ module Stores describe UserStore do - include_examples 'store', :user, %i[user provider provider_contact accredited_provider] + include_examples 'store', :user, %i[user provider provider_contact accredited_provider provider_partnership] end end diff --git a/spec/services/workflow_step_service_partnerships_spec.rb b/spec/services/workflow_step_service_partnerships_spec.rb new file mode 100644 index 0000000000..7ed3b65e7f --- /dev/null +++ b/spec/services/workflow_step_service_partnerships_spec.rb @@ -0,0 +1,201 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe WorkflowStepService do + subject do + described_class.call(course) + end + + before do + allow(Settings.features).to receive(:provider_partnerships).and_return(true) + end + + describe '#call partnerships' do + context 'when course.is_school_direct? && when course.provider.accredited_partners.length == 0' do + let(:provider) { build(:provider) } + let(:course) { create(:course, :salary) } + let(:accredited_provider) { nil } + + it 'returns the expected workflow steps' do + expected_steps = %i[ + courses_list + level + subjects + engineers_teach_physics + modern_languages + age_range + outcome + funding_type + full_or_part_time + school + study_site + accredited_provider + can_sponsor_skilled_worker_visa + applications_open + start_date + confirmation + ] + + expect(subject).to eq(expected_steps) + end + end + + context 'when course.is_school_direct? && course.provider.accredited_partners.length == 1' do + let(:provider) { build(:provider, :with_accredited_partner) } + let(:course) { create(:course, :salary, accrediting_provider: accredited_provider, provider:) } + let(:accredited_provider) { provider.accredited_partners.first } + + it 'returns the expected workflow steps' do + expected_steps = %i[ + courses_list + level + subjects + engineers_teach_physics + modern_languages + age_range + outcome + funding_type + full_or_part_time + school + study_site + can_sponsor_skilled_worker_visa + applications_open + start_date + confirmation + ] + + expect(subject).to eq(expected_steps) + end + end + end + + context 'when school direct and teacher degree apprenticeship' do + context 'when more than one accredited provider' do + let(:provider) { build(:provider) } + let(:course) { create(:course, :resulting_in_undergraduate_degree_with_qts, provider:) } + let!(:partnerships) { create_list(:provider_partnership, 2, training_provider: provider) } + let(:accredited_provider) { provider.accredited_partners.first } + let(:second_accredited_provider) { provider.accredited_partners.last } + + it 'adds accredited provider step' do + expected_steps = %i[ + courses_list + level + subjects + engineers_teach_physics + modern_languages + age_range + outcome + school + study_site + accredited_provider + applications_open + start_date + confirmation + ] + + expect(subject).to eq(expected_steps) + end + end + + context 'when only one accredited provider' do + let(:provider) { build(:provider, :with_accredited_partner) } + let(:accredited_provider) { provider.accredited_partners.first } + let(:course) { create(:course, :resulting_in_undergraduate_degree_with_qts, accrediting_provider: accredited_provider, provider:) } + + it 'removes accredited provider step' do + expected_steps = %i[ + courses_list + level + subjects + engineers_teach_physics + modern_languages + age_range + outcome + school + study_site + applications_open + start_date + confirmation + ] + + expect(subject).to eq(expected_steps) + end + end + end + + context 'when scitt and teacher degree apprenticeship' do + let(:provider) { create(:provider, :scitt, :accredited_provider) } + let(:course) { create(:course, :resulting_in_undergraduate_degree_with_qts, provider:) } + + it 'returns workflow steps' do + expected_steps = %i[ + courses_list + level + subjects + engineers_teach_physics + modern_languages + age_range + outcome + school + study_site + applications_open + start_date + confirmation + ] + + expect(subject).to eq(expected_steps) + end + end + + context 'when course.is_further_education?' do + let(:provider) { create(:provider, :accredited_provider) } + + let(:course) { create(:course, provider:, level: 'further_education', subjects: [find_or_create(:further_education_subject)]) } + + it 'returns the expected workflow steps' do + expected_steps = %i[ + courses_list + level + outcome + funding_type + full_or_part_time + school + study_site + applications_open + start_date + confirmation + ] + + expect(subject).to eq(expected_steps) + end + end + + context 'when course.is_uni_or_scitt?' do + let(:provider) { create(:provider, :accredited_provider) } + let(:course) { create(:course, :salary, provider:) } + + it 'returns the expected workflow steps' do + expected_steps = %i[ + courses_list + level + subjects + engineers_teach_physics + modern_languages + age_range + outcome + funding_type + full_or_part_time + school + study_site + can_sponsor_skilled_worker_visa + applications_open + start_date + confirmation + ] + + expect(subject).to eq(expected_steps) + end + end +end diff --git a/spec/services/workflow_step_service_spec.rb b/spec/services/workflow_step_service_spec.rb index 849a7c374a..ec0706a98f 100644 --- a/spec/services/workflow_step_service_spec.rb +++ b/spec/services/workflow_step_service_spec.rb @@ -7,6 +7,10 @@ described_class.call(course) end + before do + allow(Settings.features).to receive(:provider_partnerships).and_return(false) + end + describe '#call' do context 'when course.is_school_direct? && when course.provider.accredited_bodies.length == 0' do let(:provider) do diff --git a/spec/support/page_objects/publish/courses/ratifying_providers.rb b/spec/support/page_objects/publish/courses/ratifying_providers.rb new file mode 100644 index 0000000000..b3f4ebeadc --- /dev/null +++ b/spec/support/page_objects/publish/courses/ratifying_providers.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module PageObjects + module Publish + module Courses + class RatifyingProviders < PageObjects::Base + set_url '/publish/organisations/{provider_code}/{recruitment_cycle_year}/courses/{course_code}/ratifying-provider' + + elements :suggested_accredited_bodies, '[data-qa="course__accredited_provider_option"]' + element :add_new_link, '[data-qa="course__add"]' + + element :update_button, 'input[type=submit]' + end + end + end +end