From 65e912d5eff21f36564c9926e841ed58231adaa3 Mon Sep 17 00:00:00 2001 From: Weronika Tomaszewska Date: Mon, 2 Feb 2026 17:36:09 -0500 Subject: [PATCH] FOLIOSYNC-15 add or modify 948 MARC field and send it to FOLIO; add tests --- Gemfile | 2 - .../marc_record_enhancer.rb | 45 +++++++ .../marc_record_enhancer_spec.rb | 118 +++++++++++++++++- 3 files changed, 162 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 40d1bdf..2803928 100644 --- a/Gemfile +++ b/Gemfile @@ -55,8 +55,6 @@ group :development, :test do # Static analysis for security vulnerabilities [https://brakemanscanner.org/] gem 'brakeman', require: false - gem 'retriable', '~> 3.1' - gem 'rspec-rails', '~> 8.0.0' gem 'pry', '~> 0.15.0' diff --git a/lib/folio_sync/archives_space_to_folio/marc_record_enhancer.rb b/lib/folio_sync/archives_space_to_folio/marc_record_enhancer.rb index 4582459..a9cd06b 100644 --- a/lib/folio_sync/archives_space_to_folio/marc_record_enhancer.rb +++ b/lib/folio_sync/archives_space_to_folio/marc_record_enhancer.rb @@ -28,6 +28,7 @@ def enhance_marc_record! update_datafield_099 update_datafield_100 update_datafield_856 + add_948_field add_965_no_export_auth remove_corpname_punctuation rescue StandardError => e @@ -110,6 +111,23 @@ def update_datafield_856 end end + # OCLC sync support: Add or update datafield 948 + def add_948_field + current_date = Time.now.utc.strftime('%Y%m%d') + existing_oclc_field = find_folio_948_asoclc_field + + oclc_field = if existing_oclc_field + update_948_date(existing_oclc_field, current_date) + else + MARC::DataField.new('948', ' ', ' ', + ['a', current_date], + ['b', 'STATORGL'], + ['d', 'ASOCLC']) + end + + @marc_record.append(oclc_field) + end + # Add 965 field def add_965_no_export_auth field_965 = MARC::DataField.new('965', ' ', ' ', ['a', '965noexportAUTH']) @@ -144,6 +162,33 @@ def process_corpname_datafield(field) end end + def update_948_date(field, date) + updated_field = MARC::DataField.new( + field.tag, + field.indicator1, + field.indicator2, + *field.subfields.map { |sf| [sf.code, sf.value] } + ) + + subfield_a = updated_field.subfields.find { |sf| sf.code == 'a' } + if subfield_a + subfield_a.value = date + else + updated_field.append(MARC::Subfield.new('a', date)) + end + + updated_field + end + + def find_folio_948_asoclc_field + return nil unless @folio_marc + + @folio_marc.fields('948').find do |field| + subfield_d = field['d'] + subfield_d == 'ASOCLC' + end + end + def remove_trailing_commas(value) value.gsub(/[.]$/, '') end diff --git a/spec/folio_sync/archives_space_to_folio/marc_record_enhancer_spec.rb b/spec/folio_sync/archives_space_to_folio/marc_record_enhancer_spec.rb index bf3cf16..7c377f1 100644 --- a/spec/folio_sync/archives_space_to_folio/marc_record_enhancer_spec.rb +++ b/spec/folio_sync/archives_space_to_folio/marc_record_enhancer_spec.rb @@ -63,7 +63,7 @@ before do File.write(aspace_marc_path, aspace_mock) - File.write(folio_marc_path, folio_mock) + File.write(folio_marc_path, folio_mock) if folio_marc_path # Mock FOLIO::Reader folio_reader = instance_double(FolioSync::Folio::Reader) @@ -170,6 +170,122 @@ end end + describe '#add_948_field' do + let(:marc_record) { described_class.new(aspace_marc_path, folio_marc_path, hrid, instance_key) } + + context 'when FOLIO record has no 948 field' do + it 'creates a new 948 field with subfields a, b and d' do + marc_record.send(:add_948_field) + field_948 = marc_record.marc_record['948'] + + expect(field_948).not_to be_nil + expect(field_948['a']).to match(/\A\d{8}\z/) # YYYYMMDD format + expect(field_948['b']).to eq('STATORGL') + expect(field_948['d']).to eq('ASOCLC') + end + end + + context 'when FOLIO record has 948 field with d == ASOCLC' do + let(:folio_mock) do + <<-XML + + 7890 + + 20200101 + STATORGL + ASOCLC + + + XML + end + + it 'preserves existing subfields and updates subfield a to current date' do + marc_record.send(:add_948_field) + field_948 = marc_record.marc_record['948'] + + expect(field_948['a']).to match(/\A\d{8}\z/) + expect(field_948['a']).not_to eq('20200101') + expect(field_948['b']).to eq('STATORGL') + expect(field_948['d']).to eq('ASOCLC') + end + end + + context 'when FOLIO record has 948 field with different d value' do + let(:folio_mock) do + <<-XML + + 7890 + + 20200101 + MPS + + + XML + end + + it 'creates a new 948 field' do + marc_record.send(:add_948_field) + field_948 = marc_record.marc_record['948'] + + expect(field_948['d']).to eq('ASOCLC') + expect(field_948['b']).to eq('STATORGL') + end + end + end + + describe '#find_folio_948_asoclc_field' do + let(:marc_record) { described_class.new(aspace_marc_path, folio_marc_path, hrid, instance_key) } + + context 'when no folio_marc exists' do + let(:folio_marc_path) { nil } + + it 'returns nil' do + result = marc_record.send(:find_folio_948_asoclc_field) + expect(result).to be_nil + end + end + + context 'when folio_marc has 948 with d == ASOCLC' do + let(:folio_mock) do + <<-XML + + + 20200101 + ASOCLC + + + XML + end + + it 'returns the matching field' do + result = marc_record.send(:find_folio_948_asoclc_field) + expect(result).not_to be_nil + expect(result['d']).to eq('ASOCLC') + end + end + end + + describe '#update_948_date' do + let(:marc_record) { described_class.new(aspace_marc_path, folio_marc_path, hrid, instance_key) } + let(:field) do + MARC::DataField.new('948', ' ', ' ', + ['a', '20200101'], + ['b', 'STATORGL'], + ['d', 'ASOCLC']) + end + + it 'updates subfield a to the new date' do + result = marc_record.send(:update_948_date, field, '20260202') + expect(result['a']).to eq('20260202') + end + + it 'preserves other subfields' do + result = marc_record.send(:update_948_date, field, '20260202') + expect(result['b']).to eq('STATORGL') + expect(result['d']).to eq('ASOCLC') + end + end + describe 'helper methods' do let(:marc_record) { described_class.new(aspace_marc_path, folio_marc_path, hrid, instance_key) }