Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CPDLP-3519] Add contract for course validation to change schedule and declarations create services #1802

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions app/services/declarations/create.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ class Create
validates :declaration_date, declaration_date: true
validates :declaration_date, presence: true
validates :declaration_type, presence: true
# TODO: we don't have NPQ Contract yet
# validates :cohort, contract_for_cohort_and_course: true
validates :cohort, contract_for_cohort_and_course: true

validate :output_fee_statement_available
validate :validate_has_passed_field, if: :validate_has_passed?
Expand Down
24 changes: 12 additions & 12 deletions app/services/participants/change_schedule.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class ChangeSchedule < Action

validates :schedule_identifier, presence: true
validate :validate_new_schedule_found
# validates :cohort, npq_contract_for_cohort_and_course: true # TODO we don't have NPQ Contract yet
validates :cohort, contract_for_cohort_and_course: true
validate :validate_not_withdrawn
validate :validate_new_schedule_valid_with_existing_declarations
validate :validate_changing_to_different_schedule
Expand All @@ -28,14 +28,14 @@ def change_schedule
true
end

private

def new_cohort
@new_cohort ||= cohort ? Cohort.find_by(start_year: cohort) : fallback_cohort
def cohort
@cohort ||= super ? Cohort.find_by(start_year: super) : fallback_cohort
end

private

def new_schedule
@new_schedule ||= Schedule.find_by(identifier: schedule_identifier, cohort: new_cohort)
@new_schedule ||= Schedule.find_by(identifier: schedule_identifier, cohort:)
end

def fallback_cohort
Expand All @@ -45,16 +45,16 @@ def fallback_cohort
def update_application!
params = { schedule: new_schedule }

if application.cohort != new_cohort
params[:cohort] = new_cohort
if application.cohort != cohort
params[:cohort] = cohort
end

application.update!(params)
end

def update_funded_place!
return if application&.cohort&.funding_cap? && new_cohort.funding_cap?
return unless new_cohort.funding_cap?
return if application&.cohort&.funding_cap? && cohort.funding_cap?
return unless cohort.funding_cap?

application.update!(funded_place: application.eligible_for_funding)
end
Expand Down Expand Up @@ -118,9 +118,9 @@ def validate_changing_to_different_schedule

def validate_application_funded_place
return unless application
return unless application.cohort != new_cohort
return unless application.cohort != cohort

if application.cohort&.funding_cap? && !new_cohort.funding_cap?
if application.cohort&.funding_cap? && !cohort.funding_cap?
errors.add(:cohort, :cannot_change)
end
end
Expand Down
22 changes: 22 additions & 0 deletions app/validators/contract_for_cohort_and_course_validator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# frozen_string_literal: true

class ContractForCohortAndCourseValidator < ActiveModel::Validator
def validate(record)
return if record.errors.any?
return unless contract_for_cohort_and_course(record).empty?

record.errors.add(:cohort, :missing_contract_for_cohort_and_course)
end

private

def contract_for_cohort_and_course(record)
Contract.joins(:course, :statement).where(
courses: { identifier: record.course_identifier },
statements: {
cohort: record.cohort,
lead_provider: record.lead_provider,
},
)
end
end
2 changes: 2 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ en:

cohort: &cohort
cannot_change: "You cannot change the '#/%{parameterized_attribute}' field"
missing_contract_for_cohort_and_course: You cannot change a participant to this cohort as you do not have a contract for the cohort and course. Contact the DfE for assistance.

schedule: &schedule
cohort_mismatch: The schedule cohort must match the application cohort
Expand Down Expand Up @@ -399,6 +400,7 @@ en:
<<: *lead_provider
cohort:
<<: *statement
missing_contract_for_cohort_and_course: You cannot submit a declaration for this participant as you do not have a contract for the cohort and course. Contact the DfE for assistance.
participant_outcomes/create:
attributes:
base:
Expand Down
5 changes: 5 additions & 0 deletions spec/requests/api/docs/v1/declarations_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@
}
end

before do
statement = create(:statement, cohort:, lead_provider:)
create(:contract, statement:, course:)
end

it_behaves_like "an API create on resource endpoint documentation",
"/api/v1/participant-declarations",
"Participant declarations",
Expand Down
5 changes: 5 additions & 0 deletions spec/requests/api/docs/v1/participants_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@
end
let!(:participant) { application.user }

before do
statement = create(:statement, cohort:, lead_provider:)
create(:contract, statement:, course:)
end

it_behaves_like "an API index endpoint documentation",
"/api/v1/participants/npq",
"NPQ Participants",
Expand Down
5 changes: 5 additions & 0 deletions spec/requests/api/docs/v2/declarations_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@
}
end

before do
statement = create(:statement, cohort:, lead_provider:)
create(:contract, statement:, course:)
end

it_behaves_like "an API create on resource endpoint documentation",
"/api/v2/participant-declarations",
"Participant declarations",
Expand Down
5 changes: 5 additions & 0 deletions spec/requests/api/docs/v2/participants_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@
end
let!(:participant) { application.user }

before do
statement = create(:statement, cohort:, lead_provider:)
create(:contract, statement:, course:)
end

it_behaves_like "an API index endpoint documentation",
"/api/v2/participants/npq",
"NPQ Participants",
Expand Down
5 changes: 5 additions & 0 deletions spec/requests/api/docs/v3/declarations_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@
}
end

before do
statement = create(:statement, cohort:, lead_provider:)
create(:contract, statement:, course:)
end

it_behaves_like "an API create on resource endpoint documentation",
"/api/v3/participant-declarations",
"Participant declarations",
Expand Down
5 changes: 5 additions & 0 deletions spec/requests/api/docs/v3/participants_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@
end
let!(:participant) { application.user }

before do
statement = create(:statement, cohort:, lead_provider:)
create(:contract, statement:, course:)
end

it_behaves_like "an API index endpoint documentation",
"/api/v3/participants/npq",
"NPQ Participants",
Expand Down
9 changes: 8 additions & 1 deletion spec/services/declarations/create_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
has_passed:,
}
end
let!(:statement) { create(:statement, cohort:, lead_provider:) }
let(:statement) { create(:statement, cohort:, lead_provider:) }
let!(:contract) { create(:contract, statement:, course:) }

subject(:service) { described_class.new(**params) }

Expand Down Expand Up @@ -265,6 +266,12 @@
it { is_expected.to have_error(:cohort, :no_output_fee_statement, "You cannot submit or void declarations for the #{cohort.start_year} cohort. The funding contract for this cohort has ended. Get in touch if you need to discuss this with us.") }
end
end

context "when lead provider has no contract for the cohort and course" do
before { contract.update!(course: create(:course, :leading_literacy)) }

it { is_expected.to have_error(:cohort, :missing_contract_for_cohort_and_course, "You cannot submit a declaration for this participant as you do not have a contract for the cohort and course. Contact the DfE for assistance.") }
end
end

describe "#create_declaration" do
Expand Down
64 changes: 26 additions & 38 deletions spec/services/participants/change_schedule_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,31 @@

RSpec.describe Participants::ChangeSchedule, type: :model do
let(:cohort) { create(:cohort, :current) }
let(:params) do
{
lead_provider:,
participant_id:,
course_identifier:,
schedule_identifier: new_schedule_identifier,
cohort: nil,
}
end
let(:lead_provider) { create(:lead_provider) }
let(:course) { create(:course, :senior_leadership) }
let(:course_identifier) { course.identifier }
let(:schedule) { create(:schedule, :npq_leadership_spring, cohort:) }
let!(:application) { create(:application, :accepted, cohort:, lead_provider:, course:, schedule:) }

let(:participant) { application.user }
let(:participant_id) { participant.ecf_id }

let(:new_cohort) { create(:cohort, :next) }
let(:new_schedule) { create(:schedule, :npq_leadership_autumn, cohort: new_cohort) }
let(:new_schedule_identifier) { new_schedule.identifier }
let(:statement) { create(:statement, cohort:, lead_provider:) }
let!(:contract) { create(:contract, statement:, course:) }

let(:params) do
{
lead_provider:,
participant_id:,
course_identifier:,

schedule_identifier: new_schedule_identifier,
cohort: nil,
}
before do
new_statement = create(:statement, cohort: new_cohort, lead_provider:)
create(:contract, statement: new_statement, course:)
end

subject { described_class.new(params) }
Expand All @@ -38,7 +41,6 @@
lead_provider:,
participant_id:,
course_identifier:,

schedule_identifier: new_schedule_identifier,
cohort: new_cohort.start_year,
}
Expand All @@ -56,14 +58,9 @@
end

context "when the schedule identifier change of the same type again" do
before do
create(:schedule, :npq_leadership_autumn, cohort:)
end
let(:new_schedule) { create(:schedule, :npq_leadership_spring, cohort:) }

it "is invalid and returns an error message" do
expect(subject.change_schedule).to be_truthy
expect(subject).to have_error(:schedule_identifier, :already_on_the_profile, "Selected schedule is already on the profile")
end
it { is_expected.to have_error(:schedule_identifier, :already_on_the_profile, "Selected schedule is already on the profile") }
end
end

Expand All @@ -83,7 +80,6 @@
lead_provider:,
participant_id:,
course_identifier:,

schedule_identifier: new_schedule_identifier,
cohort: new_cohort.start_year,
}
Expand Down Expand Up @@ -272,20 +268,13 @@
end
end

# TODO: when NPQ Contract has been migrated
###########################################
# context "when lead provider has no contract for the cohort and course" do
# let(:new_cohort) { Cohort.previous }
#
# before { npq_contract.update!(npq_course: create(:npq_specialist_course)) }
#
# it "is invalid and returns an error message" do
# is_expected.to be_invalid
#
# expect(subject.errors.messages_for(:cohort)).to include("You cannot change a participant to this cohort as you do not have a contract for the cohort and course. Contact the DfE for assistance.")
# end
# end
###########################################
context "when lead provider has no contract for the cohort and course" do
let(:new_schedule) { create(:schedule, :npq_leadership_autumn, cohort:) }

before { contract.update!(course: create(:course, :leading_literacy)) }

it { is_expected.to have_error(:cohort, :missing_contract_for_cohort_and_course, "You cannot change a participant to this cohort as you do not have a contract for the cohort and course. Contact the DfE for assistance.") }
end
end

describe "#change_schedule" do
Expand Down Expand Up @@ -316,17 +305,17 @@
end

context "when schedule is nil" do
let!(:current_cohort) { create(:cohort, :current) }
let(:new_cohort) { create(:cohort, :current) }
let(:new_schedule) { create(:schedule, :npq_leadership_autumn, cohort: new_cohort) }

before do
create(:schedule, :npq_leadership_autumn, cohort: current_cohort)
application.update!(schedule: nil)
end

it "fallback to Cohort.current" do
expect(subject.change_schedule).to be_truthy
application.reload
expect(application.cohort).to eql(current_cohort)
expect(application.cohort).to eql(new_cohort)
end
end
end
Expand All @@ -338,7 +327,6 @@
lead_provider:,
participant_id:,
course_identifier:,

schedule_identifier: new_schedule_identifier,
cohort: new_cohort.start_year,
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# frozen_string_literal: true

require "rails_helper"

RSpec.describe ContractForCohortAndCourseValidator do
let(:klass) do
Class.new do
include ActiveModel::Model
include ActiveModel::Validations

validates :cohort, contract_for_cohort_and_course: true

attr_reader :cohort, :lead_provider, :course_identifier

def self.model_name
ActiveModel::Name.new(self, nil, "declarations/create")
end

def initialize(cohort:, lead_provider:, course_identifier:)
@cohort = cohort
@lead_provider = lead_provider
@course_identifier = course_identifier
end
end
end

describe "#validate" do
subject { klass.new(**params) }

let(:params) { { cohort:, lead_provider:, course_identifier: } }

let(:lead_provider) { create(:lead_provider) }
let(:course) { create(:course, :senior_leadership) }
let(:cohort) { create(:cohort, :current) }
let(:statement) { create(:statement, cohort:, lead_provider:) }
let!(:contract) { create(:contract, statement:, course:) }
let(:course_identifier) { course.identifier }

it "is valid" do
expect(subject).to be_valid
end

context "when lead provider has no contract for the cohort and course" do
before { contract.update!(course: create(:course, :leading_literacy)) }

it { is_expected.to be_invalid }
it { is_expected.to have_error(:cohort, :missing_contract_for_cohort_and_course, "You cannot submit a declaration for this participant as you do not have a contract for the cohort and course. Contact the DfE for assistance.") }
end
end
end
Loading