Skip to content

Commit

Permalink
Relax program/degree checks in the GraduationService
Browse files Browse the repository at this point in the history
**ISSUE**
Emory has indicated that they would like to process graduation records
and ETD publication even if the student provided degree does not
exactly match the program data in the registrar data.

**CHANGES**
* When an exact match cannot be found, look for student and school matches
ignoring program & degree mismatches
* Use graduation status from exact matches when possible; otherwise, use
relaxed matches if present, and log the differing data
* Relax program checking for undergaduate dual degree candidates in the
same way
  • Loading branch information
mark-dce committed Jul 19, 2022
1 parent 4c01676 commit af46d9f
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 12 deletions.
33 changes: 22 additions & 11 deletions app/services/graduation_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,20 @@ def confirm_registrar_status(candidate_etds)
# grad_record - the corresponding registrar record
def find_registrar_match(etd_solr_doc)
ppid = etd_solr_doc['depositor_ssim']&.first
school = SCHOOL_MAP[etd_solr_doc['school_tesim']&.first]
degree = DEGREE_MAP[etd_solr_doc['degree_tesim']&.first]
registrar_index = "#{ppid}-#{school}-#{degree}"
dual_major_index = "#{ppid}-UBUS-BBA" if school == 'UCOL' && degree == 'BBA'
school = SCHOOL_MAP[etd_solr_doc['school_tesim']&.first] || "no school match"
program = PROGRAM_MAP[etd_solr_doc['degree_tesim']&.first] || "no program match"
registrar_key = "#{ppid}-#{school}-#{program}"
dual_major_fragment = "#{ppid}-UBUS" # ignore program when checking for dual majors
school_fragment = "#{ppid}-#{school}" # check for student and school match

exact_match = @registrar_data[registrar_key]
school_match = @registrar_data.select { |k, _v| k.match school_fragment }.values.last unless exact_match
dual_major_match = @registrar_data.select { |k, _v| k.match dual_major_fragment }.values.last if school == 'UCOL' && !(exact_match || school_match)

grad_record = exact_match || school_match || dual_major_match || { 'degree status descr' => 'Unmatched', 'etd record key' => registrar_key.to_s }

grad_record = @registrar_data[registrar_index] || @registrar_data[dual_major_index] || { 'degree status descr' => 'Unmatched' }
grad_date = extract_date(grad_record)
log_registrar_match(etd_solr_doc, registrar_index, grad_record, grad_date)
log_registrar_match(etd_solr_doc, registrar_key, grad_record, grad_date)
[grad_date, grad_record]
end

Expand All @@ -92,16 +98,20 @@ def extract_date(grad_record)
end

# Log status data to assist auditing and reporting on this run of the GraduationService
def log_registrar_match(etd_solr_doc, registrar_index, grad_record, grad_date)
def log_registrar_match(etd_solr_doc, computed_index, grad_record, grad_date)
registrar_key = grad_record['etd record key']

case grad_record['degree status descr']

# Exact match found with valid graduation date
when /Awarded/i
msg = "awarded\", graduation_date: \"#{grad_date}"
msg = "awarded\", graduation_date: #{grad_date.strftime('%Y-%m-%d')}"
msg += ", program mismatch: #{computed_index}" if computed_index != registrar_key

# No match found in registrar data, look for similar records with matching PPID
when /Unmatched/i
ppid = etd_solr_doc['depositor_ssim']&.first
registrar_key = computed_index
id_matches = @registrar_data.select { |k, _v| k.match ppid }
msg = if id_matches.count > 0
"no match. Other records with matching PPID: " + id_matches.map { |_k, v| "#{v['etd record key']} (#{v['degree status date']})" }.join(', ')
Expand All @@ -114,21 +124,22 @@ def log_registrar_match(etd_solr_doc, registrar_index, grad_record, grad_date)
msg = "graduation pending"
end

Rails.logger.warn "GraduationService: - ETD: #{etd_solr_doc['id']}, registrar_key: #{registrar_index}, msg: \"#{msg}\""
Rails.logger.warn "GraduationService: - ETD: #{etd_solr_doc['id']}, registrar_key: #{registrar_key}, msg: \"#{msg}\""
end

# Return a filtered version of the grad record that only includes data required for potential Proquest submission
def filter_address(grad_record)
grad_record.slice('home address 1', 'home address 2', 'home address 3', 'home address city', 'home address state', 'home address postal code', 'home address country code')
end

# DEGREE_MAP: Keys = Laevigata degree codes (degree_tesim); Values = corresponding Registrar academic program codes
# PROGRAM_MAP: Keys = Laevigata degree codes (degree_tesim); Values = corresponding Registrar academic program codes
# We're using program codes to match instead of degree codes because program codes are always present in registrar data
# degree codes extracted from live data which currently include both id and term values from https://github.com/curationexperts/laevigata/blob/main/config/authorities/degree.yml#L29
# "BA", "BBA", "BS", "CRG", "DM", "DNP", "MA", "MDP", "MDV", "MPH", "MRL", "MRPL", "MS", "MSN", "MSPH", "MT", "MTS", "PHD"
# academic program codes extracted from registrar_data*.json files:
# {"BA"=>"LIBAS", "BBA"=>"BBA", "BS"=>"LIBAS", "CRG"=>"CRGGS", "DM"=>"DM", "DNP"=>"DNP", "MA"=>"MA", "MDP"=>"MDP",
# "MDV"=>"MDV", "MPH"=>"MPH", "MRPL"=>"MRPL", "MS"=>"MS", "MSN"=>"MSN", "MSPH"=>"MSPH", "MT"=>"MT", "MTS"=>"MTS", "PHD"=>"PHD"}
DEGREE_MAP = {
PROGRAM_MAP = {
"B.A." => "LIBAS", "BA" => "LIBAS",
"B.B.A." => "BBA", "BBA" => "BBA",
"B.S." => "LIBAS", "BS" => "LIBAS",
Expand Down
14 changes: 13 additions & 1 deletion spec/services/graduation_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,18 @@
expect(grad_date).to eq '2022-05-25'.to_time
end
end
describe "for program mis-matchess" do
let(:etd_solr_doc) { { 'id' => 'SameSchoolDifferentProgram', 'depositor_ssim' => ['P0000005'], 'school_tesim' => ['Laney Graduate School'], 'degree_tesim' => ['M.A.'] } }
it 'logs warning and graduates', :aggregate_failures do
allow(Rails.logger).to receive(:warn)
_grad_date, _grad_record = grad_service.find_registrar_match(etd_solr_doc)
expect(Rails.logger).to have_received(:warn).with(/SameSchoolDifferentProgram/)
expect(Rails.logger).to have_received(:warn).with(/registrar_key: P0000005-GSAS-PHD/)
expect(Rails.logger).to have_received(:warn).with(/program mismatch: P0000005-GSAS-MA/)
expect(Rails.logger).to have_received(:warn).with(/graduation_date: 2020-05-25/)
end
end

describe "for non-matches" do
let(:etd_solr_doc) { { 'id' => 'UnmatchedETD', 'depositor_ssim' => ['P0000004'], 'school_tesim' => ['Emory College'], 'degree_tesim' => ['B.S.'] } }
it 'logs warnings for near matches with the same PPID', :aggregate_failures do
Expand All @@ -95,7 +107,7 @@
end
it 'returns a dummy registrar record' do
_grad_date, grad_record = grad_service.find_registrar_match(etd_solr_doc)
expect(grad_record).to eq({ 'degree status descr' => 'Unmatched' })
expect(grad_record).to include({ 'degree status descr' => 'Unmatched' })
end
end
end
Expand Down

0 comments on commit af46d9f

Please sign in to comment.