berkeley_library-tind 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build.yml +15 -3
  3. data/.gitignore +3 -0
  4. data/.idea/inspectionProfiles/Project_Default.xml +10 -0
  5. data/.idea/tind.iml +4 -3
  6. data/CHANGES.md +6 -0
  7. data/README.md +121 -2
  8. data/berkeley_library-tind.gemspec +1 -0
  9. data/bin/alma-multiple-tind +50 -0
  10. data/bin/alma-single-tind +48 -0
  11. data/bin/save_tind_records +80 -0
  12. data/bin/tind-marc +73 -0
  13. data/lib/berkeley_library/tind/mapping/additional_datafield_process.rb +128 -0
  14. data/lib/berkeley_library/tind/mapping/alma.rb +42 -0
  15. data/lib/berkeley_library/tind/mapping/alma_base.rb +101 -0
  16. data/lib/berkeley_library/tind/mapping/alma_multiple_tind.rb +31 -0
  17. data/lib/berkeley_library/tind/mapping/alma_single_tind.rb +28 -0
  18. data/lib/berkeley_library/tind/mapping/config.rb +44 -0
  19. data/lib/berkeley_library/tind/mapping/csv_mapper.rb +35 -0
  20. data/lib/berkeley_library/tind/mapping/csv_multiple_mapper.rb +41 -0
  21. data/lib/berkeley_library/tind/mapping/data/one_to_multiple_mapping.csv +4 -0
  22. data/lib/berkeley_library/tind/mapping/data/one_to_one_mapping.csv +39 -0
  23. data/lib/berkeley_library/tind/mapping/external_tind_field.rb +103 -0
  24. data/lib/berkeley_library/tind/mapping/field_catalog.rb +146 -0
  25. data/lib/berkeley_library/tind/mapping/field_catalog_util.rb +59 -0
  26. data/lib/berkeley_library/tind/mapping/match_tind_field.rb +77 -0
  27. data/lib/berkeley_library/tind/mapping/misc.rb +69 -0
  28. data/lib/berkeley_library/tind/mapping/multiple_rule.rb +36 -0
  29. data/lib/berkeley_library/tind/mapping/single_rule.rb +143 -0
  30. data/lib/berkeley_library/tind/mapping/tind_control_subfield.rb +59 -0
  31. data/lib/berkeley_library/tind/mapping/tind_field.rb +49 -0
  32. data/lib/berkeley_library/tind/mapping/tind_field_from_leader.rb +27 -0
  33. data/lib/berkeley_library/tind/mapping/tind_field_from_multiple_map.rb +59 -0
  34. data/lib/berkeley_library/tind/mapping/tind_field_from_single_map.rb +170 -0
  35. data/lib/berkeley_library/tind/mapping/tind_field_util.rb +112 -0
  36. data/lib/berkeley_library/tind/mapping/tind_marc.rb +134 -0
  37. data/lib/berkeley_library/tind/mapping/tind_subfield_util.rb +154 -0
  38. data/lib/berkeley_library/tind/mapping/util.rb +117 -0
  39. data/lib/berkeley_library/tind/mapping.rb +1 -0
  40. data/lib/berkeley_library/tind/module_info.rb +1 -1
  41. data/lib/berkeley_library/util/files.rb +1 -2
  42. data/spec/berkeley_library/tind/mapping/additional_datafield_process_spec.rb +35 -0
  43. data/spec/berkeley_library/tind/mapping/alma_base_spec.rb +115 -0
  44. data/spec/berkeley_library/tind/mapping/alma_multiple_tind_spec.rb +20 -0
  45. data/spec/berkeley_library/tind/mapping/alma_single_tind_spec.rb +87 -0
  46. data/spec/berkeley_library/tind/mapping/alma_spec.rb +28 -0
  47. data/spec/berkeley_library/tind/mapping/config_spec.rb +19 -0
  48. data/spec/berkeley_library/tind/mapping/csv_mapper_spec.rb +27 -0
  49. data/spec/berkeley_library/tind/mapping/csv_multiple_mapper_spec.rb +27 -0
  50. data/spec/berkeley_library/tind/mapping/external_tind_field_spec.rb +45 -0
  51. data/spec/berkeley_library/tind/mapping/field_catalog_spec.rb +78 -0
  52. data/spec/berkeley_library/tind/mapping/field_catalog_util_spec.rb +57 -0
  53. data/spec/berkeley_library/tind/mapping/match_tind_field_spec.rb +25 -0
  54. data/spec/berkeley_library/tind/mapping/misc_spec.rb +51 -0
  55. data/spec/berkeley_library/tind/mapping/multiple_rule_spec.rb +44 -0
  56. data/spec/berkeley_library/tind/mapping/single_rule_spec.rb +52 -0
  57. data/spec/berkeley_library/tind/mapping/tind_control_subfield_spec.rb +96 -0
  58. data/spec/berkeley_library/tind/mapping/tind_field_from_leader_spec.rb +21 -0
  59. data/spec/berkeley_library/tind/mapping/tind_field_from_multiple_map_spec.rb +31 -0
  60. data/spec/berkeley_library/tind/mapping/tind_field_from_single_map_spec.rb +150 -0
  61. data/spec/berkeley_library/tind/mapping/tind_field_spec.rb +60 -0
  62. data/spec/berkeley_library/tind/mapping/tind_field_util_spec.rb +68 -0
  63. data/spec/berkeley_library/tind/mapping/tind_marc_spec.rb +88 -0
  64. data/spec/berkeley_library/tind/mapping/tind_subfield_util_spec.rb +48 -0
  65. data/spec/berkeley_library/tind/mapping/util_spec.rb +56 -0
  66. data/spec/berkeley_library/tind/marc/xml_writer_spec.rb +24 -0
  67. data/spec/data/mapping/991032333019706532-sru.xml +216 -0
  68. data/spec/data/mapping/one_to_multiple_mapping.csv +4 -0
  69. data/spec/data/mapping/one_to_one_mapping.csv +39 -0
  70. data/spec/data/mapping/record.xml +263 -0
  71. data/spec/data/mapping/record_not_qualified.xml +36 -0
  72. metadata +105 -2
@@ -0,0 +1,42 @@
1
+ require 'marc'
2
+
3
+ module BerkeleyLibrary
4
+ module TIND
5
+ module Mapping
6
+ class Alma
7
+ include Util
8
+
9
+ attr_reader :record
10
+
11
+ def initialize(xml_file)
12
+ @record = alma_record(xml_file)
13
+ end
14
+
15
+ def control_field
16
+ @record.fields.each { |f| return f if f.tag.to_s == '008' }
17
+ nil
18
+ end
19
+
20
+ def field_880(subfield6_value)
21
+ @record.fields.each { |f| return f if f.tag.to_s == '880' && f['6'] == subfield6_value }
22
+ nil
23
+ end
24
+
25
+ def field(tag)
26
+ @record.fields.each { |f| return f if f.tag.to_s == tag }
27
+ nil
28
+ end
29
+
30
+ private
31
+
32
+ def alma_record(xml_file)
33
+ file = File.open(xml_file)
34
+ content = file.readlines.map(&:chomp)
35
+ xml = content.join(' ')
36
+ Util.from_xml(xml)
37
+ end
38
+
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,101 @@
1
+ # 902__$d derived from current date is added in this module
2
+
3
+ module BerkeleyLibrary
4
+ module TIND
5
+ module Mapping
6
+ module AlmaBase
7
+ include BerkeleyLibrary::Logging
8
+
9
+ @collection_parameter_hash = {}
10
+ @is_barcode = false
11
+ @is_035_from_mms_id = false
12
+
13
+ class << self
14
+ attr_accessor :collection_parameter_hash
15
+ attr_accessor :is_barcode
16
+ attr_accessor :is_035_from_mms_id
17
+ end
18
+
19
+ # id can be:
20
+ # 1) Alma mms id
21
+ # 2) Oskicat No
22
+ # 3) BarCode No
23
+ # When alma record is nil or un-qualified, raise error
24
+ # Input datafields - an array of record specific datafields: for example, fft datafields, datafield 035 etc.
25
+
26
+ def base_tind_record(id, datafields, alma_record = nil)
27
+ marc_record = alma_record || alma_record_from(id)
28
+
29
+ raise ArgumentError, "#{id} has no Alma record." unless marc_record
30
+
31
+ unless Util.qualified_alma_record?(marc_record)
32
+ raise ArgumentError,
33
+ "#{id} belong to a host bibliographic record which should not be uploaded to TIND."
34
+ end
35
+
36
+ tind_record(id, marc_record, datafields)
37
+ end
38
+
39
+ # This is mainly for testing purpose, each collection can have a function to save it's record
40
+ def base_save(id, tind_record, file)
41
+ raise ArgumentError, "#{id} has no TIND record or not a qualified TIND record." unless tind_record
42
+
43
+ BerkeleyLibrary::TIND::MARC::XMLWriter.open(file) do |writer|
44
+ writer.write(tind_record)
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def alma_record_from(id)
51
+ record_id = get_record_id(id)
52
+ raise ArgumentError, "#{id} gets no BarCode or RecordId from Alma module." unless record_id
53
+
54
+ record_id.get_marc_record
55
+ end
56
+
57
+ def get_record_id(id)
58
+ AlmaBase.is_barcode ? BerkeleyLibrary::Alma::BarCode.new(id) : BerkeleyLibrary::Alma::RecordId.parse(id)
59
+ end
60
+
61
+ def derived_tind_fields(mms_id)
62
+ tind_fields = []
63
+ tind_fields << TindField.f_902_d
64
+
65
+ hash = AlmaBase.collection_parameter_hash
66
+ tind_fields.concat ExternalTindField.tind_fields_from_collection_information(hash)
67
+
68
+ tind_fields.concat ExternalTindField.tind_mms_id_fields(mms_id)
69
+
70
+ f_035 = add_f_035(mms_id, hash)
71
+ tind_fields << f_035 if f_035
72
+
73
+ tind_fields
74
+ end
75
+
76
+ def tind_record(id, marc_record, datafields)
77
+ tindmarc = TindMarc.new(marc_record)
78
+ # get all derived tind_fields: 1) from collection information; 2) from id
79
+ mms_id = tindmarc.field_catalog.mms_id
80
+ logger.warn("#{id} has no Control Field 001") unless mms_id
81
+
82
+ tind_fields = derived_tind_fields(mms_id)
83
+ # add inputted record specific datafields
84
+ tind_fields.concat datafields
85
+ tindmarc.tind_external_datafields = tind_fields
86
+
87
+ # creete a tind marc record
88
+ tindmarc.tind_record
89
+ end
90
+
91
+ def add_f_035(mms_id, hash)
92
+ return nil unless mms_id && AlmaBase.is_035_from_mms_id
93
+
94
+ val_980 = hash['980'][0].strip
95
+ TindField.f_035_from_alma_id(mms_id, val_980)
96
+ end
97
+
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,31 @@
1
+ require 'marc'
2
+ require 'berkeley_library/tind'
3
+ require 'berkeley_library/alma'
4
+ module BerkeleyLibrary
5
+ module TIND
6
+ module Mapping
7
+
8
+ class AlmaMultipleTIND
9
+ include Util
10
+ include AlmaBase
11
+ include BerkeleyLibrary::Logging
12
+
13
+ # id can be
14
+ # 1) Alma mms id
15
+ # 2) Oskicat No
16
+ # 3) BarCode No
17
+ def initialize(id)
18
+ @id = id
19
+ @marc_record = alma_record_from(id)
20
+ end
21
+
22
+ # If alma record is nil or un-qualified, it returns nil
23
+ # Input datafields - an array of record specific datafields: for example, fft datafields, datafield 035 etc.
24
+ def record(datafields)
25
+ base_tind_record(@id, datafields, @marc_record)
26
+ end
27
+
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,28 @@
1
+ require 'marc'
2
+ require 'berkeley_library/tind'
3
+ require 'berkeley_library/alma'
4
+
5
+ module BerkeleyLibrary
6
+ module TIND
7
+ module Mapping
8
+ class AlmaSingleTIND
9
+ include Util
10
+ include AlmaBase
11
+ include BerkeleyLibrary::Logging
12
+
13
+ def initialize; end
14
+
15
+ # id can be
16
+ # 1) Alma mms id
17
+ # 2) Oskicat No
18
+ # 3) BarCode No
19
+ # If alma record is nil or un-qualified, it returns nil
20
+ # Input datafields - an array of record specific datafields: for example, fft datafields, datafield 035 etc.
21
+ def record(id, datafields)
22
+ base_tind_record(id, datafields)
23
+ end
24
+
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,44 @@
1
+ require 'marc'
2
+
3
+ module BerkeleyLibrary
4
+ module TIND
5
+ module Mapping
6
+ class Config
7
+
8
+ class << self
9
+
10
+ def one_to_one_map_file
11
+ ENV.fetch('ONE_TO_ONE_MAP_FILE', File.expand_path('data/one_to_one_mapping.csv', __dir__))
12
+ end
13
+
14
+ def one_to_multiple_map_file
15
+ ENV.fetch('ONE_TO_ONE_MAP_FILE', File.expand_path('data/one_to_multiple_mapping.csv', __dir__))
16
+ end
17
+
18
+ def no_duplicated_tags
19
+ %w[245 260 852 901 902 980].freeze
20
+ end
21
+
22
+ def punctuations
23
+ %w[, : ; / =].freeze
24
+ end
25
+
26
+ def clean_tags
27
+ %w[245 260 300].freeze
28
+ end
29
+
30
+ def collection_subfield_names
31
+ {
32
+ '336' => ['a'],
33
+ '852' => ['c'],
34
+ '980' => ['a'],
35
+ '982' => ['a', 'b'],
36
+ '991' => ['a']
37
+ }.freeze
38
+ end
39
+
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,35 @@
1
+ require 'csv'
2
+ require 'berkeley_library/tind/mapping/util'
3
+
4
+ module BerkeleyLibrary
5
+ module TIND
6
+ module Mapping
7
+ module CsvMapper
8
+ @rows = []
9
+ class << self
10
+ attr_accessor :rows
11
+ end
12
+
13
+ CsvMapper.rows = Util.csv_rows(Config.one_to_one_map_file)
14
+
15
+ def from_tags
16
+ CsvMapper.rows.map { |row| row[:tag_origin] }.compact
17
+ end
18
+
19
+ def rules
20
+ CsvMapper.rows.to_h { |row| ["tag_#{row[:tag_origin]}".to_sym, SingleRule.new(row)] }
21
+ end
22
+
23
+ # tags allow to keep the first datafield from original marc record
24
+ def one_occurrence_tags
25
+ tags = []
26
+ CsvMapper.rows.each do |row|
27
+ tags << row[:tag_origin] if row[:keep_one_if_multiple_available]
28
+ end
29
+ tags.compact
30
+ end
31
+
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,41 @@
1
+ require 'csv'
2
+
3
+ module BerkeleyLibrary
4
+ module TIND
5
+ module Mapping
6
+ module CsvMultipleMapper
7
+ @rows = []
8
+ class << self
9
+ attr_accessor :rows
10
+ end
11
+
12
+ CsvMultipleMapper.rows = Util.csv_rows(Config.one_to_multiple_map_file)
13
+ def from_tags
14
+ tags = []
15
+ CsvMultipleMapper.rows.each do |row|
16
+ tag = row[:tag_origin]
17
+ tags << tag unless tags.include?(tag)
18
+ end
19
+ tags
20
+ end
21
+
22
+ def rules
23
+ from_tags.to_h { |tag| [Util.tag_symbol(tag), rules_on_tag(tag)] }
24
+ end
25
+
26
+ private
27
+
28
+ def rules_on_tag(tag)
29
+ rules = []
30
+ CsvMultipleMapper.rows.each do |row|
31
+ origin_tag = row[:tag_origin]
32
+ rules << MultipleRule.new(row) if origin_tag == tag
33
+ end
34
+
35
+ rules
36
+ end
37
+
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,4 @@
1
+ ID,tag_origin,tag_destination,map_if_no_this_tag_existed,subfield_key,new_indecator,value_from,value_to
2
+ 1,8,41,41,a,"_,_",35,37
3
+ 5,8,269,,a,"_,_",7,10
4
+ 6,LDR,903,,b,"_,_",7,7
@@ -0,0 +1,39 @@
1
+ tag_origin,tag_destination,subfield_single_from,subfield_single_to,subfield_combined_from_1,subfield_combined_to_1,symbol_1 ,subfield_combined_from_2,subfield_combined_to_2,symbol_2,subfield_combined_from_3,subfield_combined_to_3,symbol_3,New_indecator,Position_from,Position_to,Map_if_no_this_tag_existed,Map_if_no_this_tag_subfield_existed, Keep_one_if_multiple_available
2
+ 100,700,"6,e","6,e","a,b,c,d,q",a,,,,,,,,"1,_",,,,,
3
+ 110,710,"6,e","6,e","a,b",a,,,,,,,,"2,_",,,,,
4
+ 111,711,6,6,"a,c,d,e,f,n,p,t",a,,,,,,,,"_,_",,,,,
5
+ 242,246,6,6,"a,b,p,n",a,,,,,,,,,,,,,
6
+ 245,245,"6,a","6,a","n,p",p,,,,,"b,f,k",b,,"_,_",,,,,
7
+ 246,246,6,6,"a,b,p,n",a,,,,,,,,"_,_",,,,,
8
+ 250,250,"6,a","6,a",,,,,,,,,,"_,_",,,,,
9
+ 255,255,"6,a,b,c","6,a,b,c",,,,,,,,,,"_,_",,,,,
10
+ 260,260,"6,a,b,c","6,a,b,c",,,,,,,,,,"_,_",,,,,
11
+ 264,260,"6,a,b,c","6,a,b,c",,,,,,,,,,"_,_",,,260,,1
12
+ 300,300,"6,b,c","6,b,c","3,a",a,,,,,,,,"_,_",,,,,
13
+ 351,505,6,6,"a,b",a,,,,,,,,"_,_",,,,,
14
+ 490,490,6,6,"a,v",a,,,,,,,,"_,_",,,,,
15
+ 500,500,"6,a","6,a",,,,,,,,,,"_,_",,,,,
16
+ 502,502,6,6,"a,b,c,d,g,o",a,,,,,,,,"_,_",,,,,
17
+ 505,505,6,6,"a,g,r,t",a,,,,,,,,"_,_",,,,,
18
+ 507,255,"6,a","6,a",,,,,,,,,,"_,_",,,,255__a,
19
+ 520,520,"6,a","6,a",,,,,,,,,,"_,_",,,,,
20
+ 522,522,"6,a","6,a",,,,,,,,,,"_,_",,,,,
21
+ 524,524,"6,a","6,a",,,,,,,,,,"_,_",,,,,
22
+ 536,536,"6,a","6,a",,,,,,,,,,"_,_",,,,,
23
+ 541,541,6,6,"c,a,d",a,,,,,,,,"_,_",,,,,
24
+ 545,545,"6,a","6,a",,,,,,,,,,"_,_",,,,,
25
+ 546,546,"6,a","6,a",,,,,,,,,,"_,_",,,,,
26
+ 600,600,6,6,"a,b,c,d,f,j,k,l,m,n,o,p,q,r,s,t",a,,"x,y,z,v",a,a--a,,,,"_,_",,,,,
27
+ 610,610,6,6,"a,b,c,d,f,j,k,l,m,n,o,p,q,r,s,t",a,,"x,y,z,v",a,a--a,,,,"_,_",,,,,
28
+ 611,611,6,6,"a,b,c,d,f,j,k,l,m,n,o,p,q,r,s,t",a,,"x,y,z,v",a,a--a,,,,"_,_",,,,,
29
+ 630,630,6,6,"a,b,c,d,f,j,k,l,m,n,o,p,q,r,s,t",a,,"x,y,z,v",a,a--a,,,,"_,_",,,,,
30
+ 650,650,6,6,"a,b,c",a,,"x,y,z,v",a,a--a,,,,"_,_",,,,,
31
+ 651,651,6,6,a,a,,"x,y,z,v",a,a--a,,,,"_,_",,,,,
32
+ 655,655,"6,2","6,2",a,a,,"x,y,z,v",a,a--a,,,,"_,_",,,,,
33
+ 700,700,"6,e","6,e","a,b,c,d,q",a,,,,,,,,"1,_",,,,,
34
+ 710,710,"6,e","6,e","a,b",a,,,,,,,,"2,_",,,,,
35
+ 711,711,6,6,"a,c,d,e,f,n,p,t",a,,,,,,,,"_,_",,,,,
36
+ 720,700,"6,a,e","6,a,e",,,,,,,,,,"1,_",,,,,
37
+ 752,651,6,6,,,,"a,b,c,d,f,g",a,a--a,,,,"_,_",,,,,
38
+ 773,773,"6,t,j,k,o","6,t,j,k,o",,,,,,,,,,"_,_",,,,,
39
+ 907,901,"6,a","6,m",,,,,,,,,,"_,_",,,,,
@@ -0,0 +1,103 @@
1
+ require 'marc'
2
+
3
+ # Derived fields from this module
4
+ # 1) From collection information:
5
+ # 336__$a
6
+ # 852__$c
7
+ # 982__$a,b
8
+ # 991__$a
9
+ # 2) From mms_id
10
+ # 901__$m
11
+ # 85641$u,y
12
+
13
+ module BerkeleyLibrary
14
+ module TIND
15
+ module Mapping
16
+ module ExternalTindField
17
+ class << self
18
+ include BerkeleyLibrary::Logging
19
+
20
+ def tind_fields_from_collection_information(hash)
21
+ raise ArgumentError, 'Collection parameters are incorrect.' unless valid_collection_hash?(hash)
22
+
23
+ collection_fields(hash)
24
+ end
25
+
26
+ def tind_mms_id_fields(mms_id)
27
+ raise ArgumentError, 'mms_id is nil' unless mms_id
28
+
29
+ mms_id_fields(mms_id)
30
+ end
31
+
32
+ private
33
+
34
+ def collection_fields(hash)
35
+ fields = []
36
+ hash.each_key do |tag|
37
+ tindfield = tindfield_on_tag(tag, hash)
38
+ fields << tindfield if tindfield
39
+ end
40
+
41
+ fields
42
+ end
43
+
44
+ def mms_id_fields(mms_id)
45
+ fields = []
46
+ fields << tind_field_901_m(mms_id)
47
+ fields << tind_field_856_4_1(mms_id)
48
+ end
49
+
50
+ def tind_field_901_m(alma_id)
51
+ ::MARC::DataField.new('901', ' ', ' ', ['m', alma_id])
52
+ end
53
+
54
+ def tind_field_856_4_1(alma_id)
55
+ u = "https://search.library.berkeley.edu/discovery/fulldisplay?context=L&vid=01UCS_BER:UCB&docid=alma#{alma_id}"
56
+ y = 'View library catalog record.'
57
+ subfield1 = Util.subfield('u', u)
58
+ subfield2 = Util.subfield('y', y)
59
+
60
+ ::MARC::DataField.new('856', '4', '1', subfield1, subfield2)
61
+ end
62
+
63
+ def tindfield_on_tag(tag, hash)
64
+ subfield_names = Config.collection_subfield_names[tag]
65
+ subfield_values = hash[tag]
66
+ return nil if subfield_values.empty?
67
+
68
+ subfields = tind_subfields(subfield_values, subfield_names)
69
+ Util.datafield(tag, [' ', ' '], subfields)
70
+ end
71
+
72
+ def tind_subfields(subfield_values, subfield_names)
73
+ subfields = []
74
+ subfield_values.each_with_index do |value, i|
75
+ name = subfield_names[i]
76
+ subfield = Util.subfield(name, value.strip)
77
+ subfields << subfield
78
+ end
79
+ subfields
80
+ end
81
+
82
+ def valid_collection_hash?(hash)
83
+ return false unless valid_item?(hash, '336', 1) &&
84
+ valid_item?(hash, '852', 1) && valid_item?(hash, '980', 1) && valid_item?(hash, '982', 2) && valid_991(hash)
85
+
86
+ true
87
+ end
88
+
89
+ def valid_item?(hash, key, num)
90
+ (hash.key? key) && (hash[key].length == num)
91
+ end
92
+
93
+ def valid_991(hash)
94
+ cout = hash['991'].length
95
+ [0, 1].include?(cout)
96
+ end
97
+
98
+ end
99
+ end
100
+ end
101
+
102
+ end
103
+ end
@@ -0,0 +1,146 @@
1
+ require 'berkeley_library/tind/mapping/tind_subfield_util'
2
+ require 'berkeley_library/tind/mapping/misc'
3
+ require 'berkeley_library/tind/mapping/field_catalog_util'
4
+ require 'berkeley_library/tind/mapping/match_tind_field'
5
+
6
+ module BerkeleyLibrary
7
+ module TIND
8
+ module Mapping
9
+
10
+ class DataFieldsCatalog
11
+ include Misc
12
+ include TindSubfieldUtil
13
+ include CsvMapper
14
+ include Util
15
+ include AdditionalDatafieldProcess
16
+ include FieldCatalogUtil
17
+ include MatchTindField
18
+ include BerkeleyLibrary::Logging
19
+
20
+ attr_reader :control_fields
21
+ attr_reader :data_fields_group
22
+ attr_reader :data_fields_880_group
23
+ attr_reader :data_fields_880_00
24
+ attr_reader :mms_id
25
+
26
+ def initialize(record)
27
+ @control_fields = []
28
+ @data_fields_group = []
29
+ @data_fields_880_group = []
30
+ @data_fields_880_00 = []
31
+ @mms_id = ''
32
+
33
+ @data_fields = []
34
+ @data_fields_880 = []
35
+ @alma_field_tags = []
36
+
37
+ init(record)
38
+ end
39
+
40
+ def init(record)
41
+ prepare_catalog(record)
42
+ @data_fields_group = prepare_group(@data_fields)
43
+ @data_fields_880_group = prepare_group(@data_fields_880)
44
+ @mms_id = alma_mms_id
45
+ end
46
+
47
+ def prepare_catalog(record)
48
+ clean_fields = clean_subfields(record.fields)
49
+ check_abnormal_formated_subfield6(clean_fields)
50
+ allocate_fields(clean_fields)
51
+ remove_fields_with_subject_fast
52
+ end
53
+
54
+ def remove_fields_with_subject_fast
55
+ @data_fields = exluding_fields_with_fast_subject(@data_fields)
56
+ @data_fields_880 = exluding_fields_with_fast_subject(@data_fields_880)
57
+ end
58
+
59
+ private
60
+
61
+ def allocate_fields(fields)
62
+ fields.each do |f|
63
+ next if added_control_field?(f)
64
+ next if added_880_field?(f)
65
+
66
+ tag = f.tag
67
+ next unless (found_in_mapper? tag) && (no_pre_existed_field? tag)
68
+
69
+ @data_fields << f
70
+ @alma_field_tags << f.tag
71
+ end
72
+ end
73
+
74
+ # 880 field with a subfield6 including a tag belong to origin tags defined in csv file
75
+ def qualified_880_field?(f)
76
+ return false unless referred_tag(f)
77
+
78
+ found_in_mapper?(referred_tag(f))
79
+ end
80
+
81
+ def added_control_field?(f)
82
+ return false unless ::MARC::ControlField.control_tag?(f.tag)
83
+
84
+ @control_fields << f
85
+ true
86
+ end
87
+
88
+ def added_880_field?(f)
89
+ return false unless f.tag == '880'
90
+
91
+ # adding 880 datafield with "non-subfield6" to "00" group for keeping this record in TIND
92
+ # with log information, to let users correcting or removing this datafield from TIND record
93
+ @data_fields_880_00 << f unless valid_subfield6?(f)
94
+
95
+ if qualified_880_field?(f)
96
+ subfield6_endwith_00?(f) ? @data_fields_880_00 << f : @data_fields_880 << f
97
+ end
98
+
99
+ true
100
+ end
101
+
102
+ def valid_subfield6?(f)
103
+ return true if subfield6?(f)
104
+
105
+ logger.warn("880 field has no subfield 6 #{f.inspect}")
106
+
107
+ false
108
+ end
109
+
110
+ # Is the origin_tag of a field has related from_tag in csv file?
111
+ def found_in_mapper?(tag)
112
+ from_tags.include? tag
113
+ end
114
+
115
+ # If tag is listed in csv_mapper.one_occurrence_tags
116
+ # Check pre_existed field of this tag
117
+ # make sure to keep the first datafield for an one_occurrence_tag defined in csv mapping file
118
+ # def no_pre_existed_field?(tag)
119
+ # # no one-occurrence defined in csv
120
+ # return true unless one_occurrence_tags.include? tag
121
+
122
+ # # Checking the exsisting regular fields include the one-occurrence field defined in the csv
123
+ # return false if @alma_field_tags.compact.include? tag
124
+
125
+ # true
126
+ # end
127
+
128
+ def no_pre_existed_field?(tag)
129
+ # no one-occurrence defined in csv
130
+ return true unless one_occurrence_tags.include? tag
131
+
132
+ # Checking the exsisting regular fields include the one-occurrence field defined in the csv
133
+ !(@alma_field_tags.compact.include? tag)
134
+ end
135
+
136
+ def alma_mms_id
137
+ f_001 = @control_fields.find { |f| f if f.tag == '001' }
138
+ return nil unless f_001
139
+
140
+ f_001.value
141
+ end
142
+
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,59 @@
1
+ module BerkeleyLibrary
2
+ module TIND
3
+ module Mapping
4
+ module FieldCatalogUtil
5
+
6
+ # Excluding fields: subfield2 = 'fast' and tag or refered tag(880 fields) started with '6':
7
+ def exluding_fields_with_fast_subject(fields)
8
+ fields.reject { |f| excluding_field?(f) }
9
+ end
10
+
11
+ def prepare_group(from_fields)
12
+ datafields_hash = { normal: [], pre_tag: [], pre_tag_subfield: [] }
13
+ from_fields.each do |f|
14
+ # a regular field tag, or a tag value from 880 field captured from subfield6
15
+ tag = origin_mapping_tag(f)
16
+ next unless tag
17
+
18
+ rule = rules[Util.tag_symbol(tag)]
19
+
20
+ assing_field(rule, f, datafields_hash)
21
+ end
22
+
23
+ datafields_hash
24
+ end
25
+
26
+ private
27
+
28
+ def excluding_field?(f)
29
+ return false unless field_6xx?(f)
30
+ return false unless subfield2_fast(f)
31
+
32
+ true
33
+ end
34
+
35
+ # Both regular and 880 field: tag or refered tag started with '6'
36
+ def field_6xx?(f)
37
+ tag = origin_mapping_tag(f)
38
+ tag =~ /^6\d{2}$/
39
+ end
40
+
41
+ def subfield2_fast(f)
42
+ subject = f['2']
43
+ return false unless subject
44
+
45
+ subject.downcase == 'fast'
46
+ end
47
+
48
+ # f is either from field whose tag having a match in csv mapping file - 'from tag' column
49
+ def assing_field(rule, f, datafields_hash)
50
+ if rule.pre_existed_tag then datafields_hash[:pre_tag] << f
51
+ elsif rule.pre_existed_tag_subfield then datafields_hash[:pre_tag_subfield] << f
52
+ else datafields_hash[:normal] << f
53
+ end
54
+ end
55
+
56
+ end
57
+ end
58
+ end
59
+ end