Skip to content

Commit

Permalink
[CPDLP-3933] Importers::CreateMentorCallOffContract service
Browse files Browse the repository at this point in the history
  • Loading branch information
mooktakim committed Jan 14, 2025
1 parent d2cbc34 commit 99d45b7
Show file tree
Hide file tree
Showing 8 changed files with 289 additions and 5 deletions.
8 changes: 8 additions & 0 deletions app/models/finance/statement/ecf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ def contract
)
end

def mentor_contract
MentorCallOffContract.find_by!(
version: contract_version,
cohort:,
lead_provider:,
)
end

def payable!
update!(type: "Finance::Statement::ECF::Payable")
end
Expand Down
1 change: 1 addition & 0 deletions app/models/lead_provider.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class LeadProvider < ApplicationRecord
has_many :partnership_csv_uploads
has_many :lead_provider_api_tokens
has_one :call_off_contract
has_many :mentor_call_off_contracts

has_many :statements, through: :cpd_lead_provider, class_name: "Finance::Statement::ECF", source: :ecf_statements
validates :name, presence: { message: "Enter a name" }
Expand Down
108 changes: 108 additions & 0 deletions app/services/importers/create_mentor_call_off_contract.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# frozen_string_literal: true

require "csv"

module Importers
class CreateMentorCallOffContract
def call
logger.info "CreateMentorCallOffContract: Started!"

if path_to_csv.present?
create_mentor_call_off_contract_from_csv
else
create_default_mentor_call_off_contracts
end

logger.info "CreateMentorCallOffContract: Finished!"
end

private

attr_reader :path_to_csv, :logger

def initialize(path_to_csv: nil, logger: Rails.logger)
@path_to_csv = path_to_csv
@logger = logger
end

def create_default_mentor_call_off_contracts
raise "Do not seed default Mentor Call Off Contracts in Production!" if Rails.env.production?

LeadProvider.find_each do |lead_provider|
[cohort_current, cohort_previous, cohort_next].each do |cohort|
create_mentor_call_off_contract(lead_provider:, cohort:, contract_data: example_contract_data)
end
end
end

def create_mentor_call_off_contract_from_csv
check_headers!

ActiveRecord::Base.transaction do
rows.each do |row|
cohort = Cohort.find_by!(start_year: row["cohort-start-year"].to_i)
lead_provider = LeadProvider.joins(:cohorts).find_by!(name: row["lead-provider-name"], cohorts: { start_year: row["cohort-start-year"].to_i })

mentor_call_off_contract = MentorCallOffContract.find_by(
lead_provider:,
cohort:,
)

next if mentor_call_off_contract

contract_data = build_contract_data(row)
create_mentor_call_off_contract(lead_provider:, cohort:, contract_data:)
end
end
end

def create_mentor_call_off_contract(lead_provider:, cohort:, contract_data:)
logger.info "CreateMentorCallOffContract: Adding Mentor Call Off Contract for Lead Provider: #{lead_provider.name} in cohort: #{cohort.start_year}"

MentorCallOffContract.create!(
lead_provider:,
cohort:,
recruitment_target: contract_data[:recruitment_target],
payment_per_participant: contract_data[:payment_per_participant],
)

logger.info "CreateMentorCallOffContract: Added Mentor Call Off Contract for Lead Provider: #{lead_provider.name} in cohort: #{cohort.start_year} successfully!"
end

def check_headers!
unless %w[lead-provider-name cohort-start-year recruitment-target payment-per-participant].all? { |header| rows.headers.include?(header) }
raise NameError, "Invalid headers"
end
end

def rows
@rows ||= CSV.read(path_to_csv, headers: true)
end

def cohort_current
@cohort_current ||= Cohort.current || FactoryBot.create(:cohort, :current)
end

def cohort_previous
@cohort_previous ||= Cohort.previous || FactoryBot.create(:cohort, :previous)
end

def cohort_next
@cohort_next ||= Cohort.next || FactoryBot.create(:cohort, :next)
end

def example_contract_data
@example_contract_data ||= {
recruitment_target: 4500,
payment_per_participant: 1000.0,
}
end

def build_contract_data(row)
{
recruitment_target: row["recruitment-target"],
payment_per_participant: row["payment-per-participant"],
}
end
end
end
1 change: 1 addition & 0 deletions db/legacy_seeds/test_data.rb
Original file line number Diff line number Diff line change
Expand Up @@ -699,4 +699,5 @@ def create_participant_with_eligibility(urn, name, participant_class, options =
end

Importers::CreateCallOffContract.new.call
Importers::CreateMentorCallOffContract.new.call
Importers::CreateStatement.new(path_to_csv: Rails.root.join("db/data/statements/statements.csv")).call
1 change: 1 addition & 0 deletions db/new_seeds/base/add_contracts.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# frozen_string_literal: true

Importers::CreateCallOffContract.new.call
Importers::CreateMentorCallOffContract.new.call
2 changes: 1 addition & 1 deletion spec/factories/mentor_call_off_contracts.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@

recruitment_target { 6000 }
payment_per_participant { 1000.0 }
version { "0.0.1" }
version { "1.0" }
end
end
26 changes: 22 additions & 4 deletions spec/models/finance/statement/ecf_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@
require "rails_helper"

RSpec.describe Finance::Statement::ECF do
let(:call_off_contract) { create(:call_off_contract) }
let(:ecf_lead_provider) { create(:lead_provider, call_off_contract:) }
let(:cpd_lead_provider) { create(:cpd_lead_provider, lead_provider: ecf_lead_provider) }
subject { create(:ecf_statement, cpd_lead_provider:) }
let(:cohort) { Cohort.current || create(:cohort, :current) }
let(:cpd_lead_provider) { create(:cpd_lead_provider, :with_lead_provider) }
let(:lead_provider) { cpd_lead_provider.lead_provider }

let(:contract_version) { "0.0.2" }

let!(:call_off_contract) { create(:call_off_contract, cohort:, lead_provider:, version: contract_version) }
let!(:mentor_call_off_contract) { create(:mentor_call_off_contract, cohort:, lead_provider:, version: contract_version) }

subject { create(:ecf_statement, cpd_lead_provider:, cohort:, contract_version:) }

describe "#payable!" do
it "transitions the statement to payable" do
Expand All @@ -15,4 +21,16 @@
}.to change(subject, :type).from("Finance::Statement::ECF").to("Finance::Statement::ECF::Payable")
end
end

describe "#contract" do
it "returns call_off_contract" do
expect(subject.contract).to eq(call_off_contract)
end
end

describe "#mentor_contract" do
it "returns mentor_call_off_contract" do
expect(subject.mentor_contract).to eq(mentor_call_off_contract)
end
end
end
147 changes: 147 additions & 0 deletions spec/services/importers/create_mentor_call_off_contract_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# frozen_string_literal: true

require "tempfile"

RSpec.describe Importers::CreateMentorCallOffContract do
let(:csv) { Tempfile.new("data.csv") }
let(:path_to_csv) { csv.path }

subject(:importer) { described_class.new(path_to_csv:) }

describe "#call" do
context "when no csv given" do
let(:path_to_csv) {}
let!(:lead_provider_1) { create(:lead_provider, name: "Penguin Institute") }
let!(:lead_provider_2) { create(:lead_provider, name: "Apples") }

it "creates seed mentor call off contracts for all lead providers in three cohorts" do
expect { importer.call }.to change(MentorCallOffContract, :count).by(6)
end

context "when in production env" do
before do
allow(Rails).to receive(:env).and_return ActiveSupport::EnvironmentInquirer.new("production")
end

it "raises an error and does not create records" do
expect { importer.call }.to raise_error(RuntimeError, /do not seed default mentor call off contracts in production/i)
expect(MentorCallOffContract.count).to be_zero
end
end
end

context "when csv given" do
context "when csv headers invalid" do
before do
csv.write "some-other-column,cohort-start-year"
csv.write "\n"
csv.write "Arctic Wolf Institute,2021"
csv.write "\n"
csv.close
end

it "raises an error" do
expect { importer.call }.to raise_error(NameError)
end
end

context "when lead provider does not exist" do
let!(:cohort_2021) { create(:cohort, start_year: 2021) }
before do
csv.write "lead-provider-name,cohort-start-year,recruitment-target,payment-per-participant"
csv.write "\n"
csv.write "Aardvark Institute,2021,9999,333.0"
csv.write "\n"
csv.close
end

it "raises an error" do
expect { importer.call }.to raise_error(ActiveRecord::RecordNotFound)
end
end

context "when cohort does not exist" do
let(:year_without_cohort) { Cohort.ordered_by_start_year.last.start_year + 2000 }
let!(:lead_provider) { create(:lead_provider, name: "Koala Institute") }
before do
csv.write "lead-provider-name,cohort-start-year,recruitment-target,payment-per-participant"
csv.write "\n"
csv.write "#{lead_provider.name},#{year_without_cohort},2021,9999,333.0"
csv.write "\n"
csv.close
end

it "raises an error" do
expect { importer.call }.to raise_error(ActiveRecord::RecordNotFound)
end
end

context "when lead provider does not belong in supplied cohort" do
let!(:lead_provider) { create(:lead_provider, name: "Kangaroo Institute", cohorts: []) }
let!(:cohort) { create :cohort }
before do
csv.write "lead-provider-name,cohort-start-year,recruitment-target,payment-per-participant"
csv.write "\n"
csv.write "#{lead_provider.name},#{cohort.start_year},9999,333.0"
csv.write "\n"
csv.close
end

it "raises an error" do
expect { importer.call }.to raise_error(ActiveRecord::RecordNotFound)
end
end

context "when the lead provider has an existing mentor call off contract in the cohort" do
let!(:cohort) { create :seed_cohort }
let!(:lead_provider) { create(:lead_provider, name: "Whale Institute", cohorts: [cohort]) }
let!(:mentor_call_off_contract) { create(:mentor_call_off_contract, cohort:, lead_provider:) }
before do
csv.write "lead-provider-name,cohort-start-year,recruitment-target,payment-per-participant"
csv.write "\n"
csv.write "#{lead_provider.name},#{cohort.start_year},9999,333.0"
csv.write "\n"
csv.close
end

it "does not create a new call off contract" do
expect { importer.call }.to not_change(MentorCallOffContract, :count)
end

it "does not create participant bands" do
expect { importer.call }.to not_change(ParticipantBand, :count)
end
end

context "when no mentor call off contract exists for lead provider" do
let!(:cohort) { create :cohort }
let!(:lead_provider) { create(:lead_provider, name: "Butterfly Institute", cohorts: [cohort]) }
before do
csv.write "lead-provider-name,cohort-start-year,recruitment-target,payment-per-participant"
csv.write "\n"
csv.write "#{lead_provider.name},#{cohort.start_year},9999,333.0"
csv.write "\n"
csv.close
end

it "creates a new mentor call off contract" do
expect { importer.call }.to change(MentorCallOffContract, :count).by(1)
end

it "sets the mentor call off contract version" do
importer.call
expect(lead_provider.mentor_call_off_contracts.first.version).to eq("0.0.1")
end

it "sets the correct values on the mentor call off contract" do
importer.call
expect(lead_provider.mentor_call_off_contracts.first).to have_attributes(
cohort:,
recruitment_target: 9999,
payment_per_participant: 333.0,
)
end
end
end
end
end

0 comments on commit 99d45b7

Please sign in to comment.