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) }