Skip to content

Commit 6e68af6

Browse files
committed
Implement Role sync to Salesforce
1 parent 3209c41 commit 6e68af6

7 files changed

Lines changed: 151 additions & 0 deletions

File tree

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# frozen_string_literal: true
2+
3+
module Salesforce
4+
class RoleSyncJob < SalesforceSyncJob
5+
MODEL_CLASS = Salesforce::Role
6+
7+
FIELD_MAPPINGS = {
8+
affiliation_id__c: :id,
9+
contact__r__pi_accounts_unique_id__c: :user_id,
10+
editor__r__editoruuid__c: :school_id,
11+
roletype__c: :role,
12+
createdat__c: :created_at,
13+
updatedat__c: :updated_at
14+
}.freeze
15+
16+
def perform(role_id:)
17+
role = ::Role.find(role_id)
18+
19+
return if role.student?
20+
21+
sf_role = Salesforce::Role.find_or_initialize_by(affiliation_id__c: role_id)
22+
sf_role.attributes = sf_role_attributes(role:)
23+
sf_role.save!
24+
end
25+
26+
private
27+
28+
def sf_role_attributes(role:)
29+
mapped_attributes(role:).to_h do |sf_field, value|
30+
value = truncate_value(sf_field:, value:) if value.is_a?(String)
31+
32+
[sf_field, value]
33+
end
34+
end
35+
36+
def mapped_attributes(role:)
37+
FIELD_MAPPINGS.transform_values do |role_field|
38+
role.send(role_field)
39+
end
40+
end
41+
end
42+
end

app/models/role.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ class Role < ApplicationRecord
1616
}
1717
)
1818

19+
after_commit :do_salesforce_sync, on: %i[create update]
20+
1921
private
2022

2123
def students_cannot_have_additional_roles
@@ -38,4 +40,10 @@ def users_can_only_have_roles_in_one_school
3840

3941
errors.add(:base, 'Cannot create role as this user already has a role in a different school')
4042
end
43+
44+
def do_salesforce_sync
45+
return unless ENV.fetch('SALESFORCE_ENABLED', 'true') == 'true'
46+
47+
Salesforce::RoleSyncJob.perform_later(role_id: id)
48+
end
4149
end

app/models/salesforce/role.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# frozen_string_literal: true
2+
3+
module Salesforce
4+
class Role < Salesforce::Base
5+
self.table_name = 'salesforce.contact_editor_affiliation__c'
6+
self.primary_key = :affiliation_id__c
7+
end
8+
end

lib/tasks/salesforce_sync.rake

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,11 @@ namespace :salesforce_sync do
77
Salesforce::SchoolSyncJob.perform_later(school_id:)
88
end
99
end
10+
11+
desc 'Sync all Roles to Salesforce'
12+
task role: :environment do
13+
Role.pluck(:id).each do |role_id|
14+
Salesforce::RoleSyncJob.perform_later(role_id:)
15+
end
16+
end
1017
end

spec/factories/salesforce/role.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# frozen_string_literal: true
2+
3+
FactoryBot.define do
4+
factory(:salesforce_role, class: 'Salesforce::Role') do
5+
sequence(:affiliation_id__c)
6+
end
7+
end
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# frozen_string_literal: true
2+
3+
require 'rails_helper'
4+
5+
RSpec.describe Salesforce::RoleSyncJob do
6+
subject(:perform_job) { described_class.perform_now(role_id: role.id) }
7+
8+
let(:role) { create(:role) }
9+
10+
context 'when the job has run' do
11+
before { perform_job }
12+
13+
it 'syncs all FIELD_MAPPINGS to the correct role values' do
14+
sf_role = Salesforce::Role.find_by(affiliation_id__c: role.id)
15+
described_class::FIELD_MAPPINGS.each do |sf_field, role_field|
16+
expected = Salesforce::Role.type_for_attribute(sf_field).cast(role.send(role_field))
17+
expect(sf_role.send(sf_field)).to eq(expected),
18+
"Expected #{sf_field} to equal role.#{role_field}"
19+
end
20+
end
21+
end
22+
23+
context 'when the Salesforce role fails to save' do
24+
let(:sf_role) { instance_double(Salesforce::Role) }
25+
26+
before do
27+
allow(Salesforce::Role).to receive(:find_or_initialize_by).with(affiliation_id__c: role.id).and_return(sf_role)
28+
allow(sf_role).to receive(:attributes=)
29+
allow(sf_role).to receive(:save!).and_raise(ActiveRecord::RecordInvalid)
30+
end
31+
32+
it 'raises an error' do
33+
expect { perform_job }.to raise_error ActiveRecord::RecordInvalid
34+
end
35+
end
36+
37+
context 'when the role is a student role' do
38+
let(:role) { create(:student_role) }
39+
40+
it 'does not create a Salesforce role record' do
41+
perform_job
42+
expect(Salesforce::Role.find_by(affiliation_id__c: role.id)).to be_nil
43+
end
44+
end
45+
46+
context 'when SALESFORCE_ENABLED is false' do
47+
around do |example|
48+
ClimateControl.modify(SALESFORCE_ENABLED: 'false') do
49+
example.run
50+
end
51+
end
52+
53+
it 'discards the job without syncing' do
54+
perform_job
55+
expect(Salesforce::Role.find_by(affiliation_id__c: role.id)).to be_nil
56+
end
57+
end
58+
end

spec/models/role_spec.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,4 +165,25 @@
165165
end
166166
end
167167
end
168+
169+
describe 'salesforce sync' do
170+
it 'enqueues a Salesforce::RoleSyncJob on create' do
171+
expect { create(:role) }.to have_enqueued_job(Salesforce::RoleSyncJob)
172+
end
173+
174+
it 'enqueues a Salesforce::RoleSyncJob on update' do
175+
role = create(:role)
176+
expect { role.update!(role: 'teacher') }.to have_enqueued_job(Salesforce::RoleSyncJob)
177+
end
178+
179+
context 'when SALESFORCE_ENABLED is false' do
180+
around do |example|
181+
ClimateControl.modify(SALESFORCE_ENABLED: 'false') { example.run }
182+
end
183+
184+
it 'does not enqueue Salesforce::RoleSyncJob on create' do
185+
expect { create(:role) }.not_to have_enqueued_job(Salesforce::RoleSyncJob)
186+
end
187+
end
188+
end
168189
end

0 commit comments

Comments
 (0)