berkeley_library-tind 0.5.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) 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 +10 -9
  6. data/.rubocop.yml +1 -1
  7. data/CHANGES.md +15 -1
  8. data/README.md +165 -2
  9. data/berkeley_library-tind.gemspec +2 -2
  10. data/bin/alma-multiple-tind +50 -0
  11. data/bin/alma-single-tind +48 -0
  12. data/bin/save_tind_records +80 -0
  13. data/bin/tind-marc +73 -0
  14. data/lib/berkeley_library/tind/export/ods_exporter.rb +4 -6
  15. data/lib/berkeley_library/tind/mapping/additional_datafield_process.rb +128 -0
  16. data/lib/berkeley_library/tind/mapping/alma.rb +42 -0
  17. data/lib/berkeley_library/tind/mapping/alma_base.rb +108 -0
  18. data/lib/berkeley_library/tind/mapping/alma_multiple_tind.rb +31 -0
  19. data/lib/berkeley_library/tind/mapping/alma_single_tind.rb +28 -0
  20. data/lib/berkeley_library/tind/mapping/config.rb +44 -0
  21. data/lib/berkeley_library/tind/mapping/csv_mapper.rb +35 -0
  22. data/lib/berkeley_library/tind/mapping/csv_multiple_mapper.rb +41 -0
  23. data/lib/berkeley_library/tind/mapping/data/one_to_multiple_mapping.csv +4 -0
  24. data/lib/berkeley_library/tind/mapping/data/one_to_one_mapping.csv +39 -0
  25. data/lib/berkeley_library/tind/mapping/external_tind_field.rb +103 -0
  26. data/lib/berkeley_library/tind/mapping/field_catalog.rb +137 -0
  27. data/lib/berkeley_library/tind/mapping/field_catalog_util.rb +105 -0
  28. data/lib/berkeley_library/tind/mapping/match_tind_field.rb +77 -0
  29. data/lib/berkeley_library/tind/mapping/misc.rb +69 -0
  30. data/lib/berkeley_library/tind/mapping/multiple_rule.rb +36 -0
  31. data/lib/berkeley_library/tind/mapping/single_rule.rb +149 -0
  32. data/lib/berkeley_library/tind/mapping/tind_control_subfield.rb +59 -0
  33. data/lib/berkeley_library/tind/mapping/tind_field.rb +49 -0
  34. data/lib/berkeley_library/tind/mapping/tind_field_from_leader.rb +27 -0
  35. data/lib/berkeley_library/tind/mapping/tind_field_from_multiple_map.rb +59 -0
  36. data/lib/berkeley_library/tind/mapping/tind_field_from_single_map.rb +182 -0
  37. data/lib/berkeley_library/tind/mapping/tind_field_util.rb +112 -0
  38. data/lib/berkeley_library/tind/mapping/tind_marc.rb +134 -0
  39. data/lib/berkeley_library/tind/mapping/tind_record_util.rb +135 -0
  40. data/lib/berkeley_library/tind/mapping/tind_subfield_util.rb +154 -0
  41. data/lib/berkeley_library/tind/mapping/util.rb +136 -0
  42. data/lib/berkeley_library/tind/mapping.rb +1 -0
  43. data/lib/berkeley_library/tind/module_info.rb +1 -1
  44. data/spec/berkeley_library/tind/mapping/additional_datafield_process_spec.rb +35 -0
  45. data/spec/berkeley_library/tind/mapping/alma_base_spec.rb +115 -0
  46. data/spec/berkeley_library/tind/mapping/alma_multiple_tind_spec.rb +20 -0
  47. data/spec/berkeley_library/tind/mapping/alma_single_tind_spec.rb +87 -0
  48. data/spec/berkeley_library/tind/mapping/alma_spec.rb +28 -0
  49. data/spec/berkeley_library/tind/mapping/config_spec.rb +19 -0
  50. data/spec/berkeley_library/tind/mapping/csv_mapper_spec.rb +27 -0
  51. data/spec/berkeley_library/tind/mapping/csv_multiple_mapper_spec.rb +27 -0
  52. data/spec/berkeley_library/tind/mapping/external_tind_field_spec.rb +45 -0
  53. data/spec/berkeley_library/tind/mapping/field_catalog_spec.rb +78 -0
  54. data/spec/berkeley_library/tind/mapping/field_catalog_util_spec.rb +105 -0
  55. data/spec/berkeley_library/tind/mapping/match_tind_field_spec.rb +24 -0
  56. data/spec/berkeley_library/tind/mapping/misc_spec.rb +51 -0
  57. data/spec/berkeley_library/tind/mapping/multiple_rule_spec.rb +44 -0
  58. data/spec/berkeley_library/tind/mapping/single_rule_spec.rb +52 -0
  59. data/spec/berkeley_library/tind/mapping/tind_control_subfield_spec.rb +96 -0
  60. data/spec/berkeley_library/tind/mapping/tind_field_from_leader_spec.rb +21 -0
  61. data/spec/berkeley_library/tind/mapping/tind_field_from_multiple_map_spec.rb +31 -0
  62. data/spec/berkeley_library/tind/mapping/tind_field_from_single_map_spec.rb +167 -0
  63. data/spec/berkeley_library/tind/mapping/tind_field_spec.rb +60 -0
  64. data/spec/berkeley_library/tind/mapping/tind_field_util_spec.rb +68 -0
  65. data/spec/berkeley_library/tind/mapping/tind_marc_spec.rb +88 -0
  66. data/spec/berkeley_library/tind/mapping/tind_record_util_spec.rb +30 -0
  67. data/spec/berkeley_library/tind/mapping/tind_subfield_util_spec.rb +48 -0
  68. data/spec/berkeley_library/tind/mapping/util_spec.rb +56 -0
  69. data/spec/berkeley_library/tind/marc/xml_writer_spec.rb +24 -0
  70. data/spec/data/api/pre_assigned_response.json +15 -0
  71. data/spec/data/api/result_file.csv +3 -0
  72. data/spec/data/api/upload_file.json +1 -0
  73. data/spec/data/api/upload_response.json +13 -0
  74. data/spec/data/mapping/991032333019706532-sru.xml +216 -0
  75. data/spec/data/mapping/one_to_multiple_mapping.csv +4 -0
  76. data/spec/data/mapping/one_to_one_mapping.csv +39 -0
  77. data/spec/data/mapping/record.xml +266 -0
  78. data/spec/data/mapping/record_not_qualified.xml +36 -0
  79. metadata +89 -54
  80. data/lib/berkeley_library/util/files.rb +0 -39
@@ -0,0 +1,128 @@
1
+ # 1. Combine repeated fields
2
+ # 2. Remove characters pre_defined
3
+ module BerkeleyLibrary
4
+ module TIND
5
+ module Mapping
6
+ module AdditionalDatafieldProcess
7
+
8
+ # process 1: remove and combine repeated fields - defined in Config module
9
+ def remove_repeats(fields)
10
+ Config.no_duplicated_tags.each { |tag| remove_repeated_fields(tag, fields) }
11
+ fields
12
+ end
13
+
14
+ # process 2: remove charaters in subfields defined in Config module
15
+ def clean_subfields(fields)
16
+ fields.each do |f|
17
+ next unless field_in_tags?(f, Config.clean_tags)
18
+
19
+ clean_subfields_in_field(f)
20
+ end
21
+ fields
22
+ end
23
+
24
+ # 1. Find all datafield with the tag,
25
+ # if more than one found, combine repeated datafields which have a same tag into one
26
+ # 2. Find all 880 datafields with subfield6 referring to the tag,
27
+ # if more than one found, combine repeated datafields with one subfield 6,
28
+ # a related datafield will be modified to have the same sequence in subfield 6 as in this 880 subfield 6
29
+ def remove_repeated_fields(tag, fields)
30
+ repeated_fields = fields_on_tag(tag, fields)
31
+ remove_repeated(repeated_fields, fields)
32
+
33
+ repeated_880_fields = fields_880_on_subfield6_referredtag(tag, fields)
34
+ remove_repeated(repeated_880_fields, fields)
35
+ fields
36
+ end
37
+
38
+ # clean subfields of a datafield
39
+ def clean_subfields_in_field(field)
40
+ field.subfields.each { |sf| clean_subfield(sf) }
41
+ end
42
+
43
+ private
44
+
45
+ def field_in_tags?(field, tags)
46
+ tag = field.tag
47
+ tag_to_match = tag == '880' ? referred_tag(field) : tag
48
+ return false unless tag_to_match
49
+
50
+ tags.include? tag_to_match
51
+ end
52
+
53
+ def fields_on_tag(tag, fields)
54
+ fields.select { |f| f.tag == tag }
55
+ end
56
+
57
+ def fields_880_on_subfield6_referredtag(tag, fields)
58
+ fields.select { |f| field_880_has_referred_tag?(tag, f) }
59
+ end
60
+
61
+ # Marc with tag in 'Config.no_duplicated_tags' are not supposed to have the same multiple subfields
62
+ # but sometime, sourc data error happens
63
+ # solution:
64
+ # taking the first subfield 6
65
+ # taking the first other subfield when there are multiple same subfields
66
+ # if 880 and regular field having unmatching subfield 6 in sequnce number, they will go to log file
67
+ # A user will check the log and correct data in Alma or TIND accordingly
68
+ def combined_subfields(fields)
69
+ sf_arr = []
70
+ subfield_6 = the_first_subfield6(fields)
71
+ sf_arr << subfield_6 if subfield_6
72
+ identical_subfields = no_duplicated_first_subfields(fields)
73
+ sf_arr.concat identical_subfields
74
+ sf_arr
75
+ end
76
+
77
+ # if there are multiple same subfields, pick up the first one, ignore the others
78
+ def no_duplicated_first_subfields(fields)
79
+ indentical_subfields = []
80
+
81
+ fields.each do |f|
82
+ subfields = subfields_without_subfield6(f)
83
+ subfields.each { |sf| indentical_subfields << sf if not_in_identical_subfields?(indentical_subfields, sf) }
84
+ end
85
+
86
+ indentical_subfields
87
+ end
88
+
89
+ def subfield_codes(subfields)
90
+ subfields.map(&:code)
91
+ end
92
+
93
+ def not_in_identical_subfields?(subfields, subfield)
94
+ !subfield_codes(subfields).include? subfield.code
95
+ end
96
+
97
+ # return a combined datafield from repeated datafields - with the same tag
98
+ def identical_field(repeated_fields)
99
+ tag = repeated_fields[0].tag
100
+ indicator = first_indicator(repeated_fields)
101
+ subfield_arr = combined_subfields(repeated_fields)
102
+ Util.datafield(tag, indicator, subfield_arr)
103
+ end
104
+
105
+ # remove repeated fields
106
+ def rm_fields(fields_tobe_removed, fields)
107
+ fields.delete_if { |f| fields_tobe_removed.include? f }
108
+ end
109
+
110
+ # suppose all repeated datafield have the same indictor
111
+ def first_indicator(fields)
112
+ indicator1 = fields[0].indicator1
113
+ indicator2 = fields[0].indicator2
114
+ [indicator1, indicator2]
115
+ end
116
+
117
+ # remove and keep one repeated datafield
118
+ def remove_repeated(repeated_fields, fields)
119
+ return fields unless repeated_fields.length > 1
120
+
121
+ rm_fields(repeated_fields, fields)
122
+ fields << identical_field(repeated_fields)
123
+ fields
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
@@ -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,108 @@
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
+ @including_origin_tags = []
13
+ @excluding_origin_tags = []
14
+
15
+ class << self
16
+ attr_accessor :collection_parameter_hash
17
+ attr_accessor :is_barcode
18
+ attr_accessor :is_035_from_mms_id
19
+ attr_accessor :including_origin_tags
20
+ attr_accessor :excluding_origin_tags
21
+
22
+ end
23
+
24
+ # id can be:
25
+ # 1) Alma mms id
26
+ # 2) Oskicat No
27
+ # 3) BarCode No
28
+ # When alma record is nil or un-qualified, raise error
29
+ # Input datafields - an array of record specific datafields: for example, fft datafields, datafield 035 etc.
30
+
31
+ def base_tind_record(id, datafields, alma_record = nil)
32
+ marc_record = alma_record || alma_record_from(id)
33
+
34
+ raise ArgumentError, "#{id} has no Alma record." unless marc_record
35
+
36
+ unless Util.qualified_alma_record?(marc_record)
37
+ raise ArgumentError,
38
+ "#{id} belong to a host bibliographic record which should not be uploaded to TIND."
39
+ end
40
+
41
+ tind_record(id, marc_record, datafields)
42
+ end
43
+
44
+ # This is mainly for testing purpose, each collection can have a function to save it's record
45
+ def base_save(id, tind_record, file)
46
+ raise ArgumentError, "#{id} has no TIND record or not a qualified TIND record." unless tind_record
47
+
48
+ BerkeleyLibrary::TIND::MARC::XMLWriter.open(file) do |writer|
49
+ writer.write(tind_record)
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ def alma_record_from(id)
56
+ record_id = get_record_id(id)
57
+ raise ArgumentError, "#{id} gets no BarCode or RecordId from Alma module." unless record_id
58
+
59
+ record_id.get_marc_record
60
+ end
61
+
62
+ def get_record_id(id)
63
+ AlmaBase.is_barcode ? BerkeleyLibrary::Alma::BarCode.new(id) : BerkeleyLibrary::Alma::RecordId.parse(id)
64
+ end
65
+
66
+ def derived_tind_fields(mms_id)
67
+ tind_fields = []
68
+ tind_fields << TindField.f_902_d
69
+
70
+ hash = AlmaBase.collection_parameter_hash
71
+ tind_fields.concat ExternalTindField.tind_fields_from_collection_information(hash)
72
+
73
+ tind_fields.concat ExternalTindField.tind_mms_id_fields(mms_id)
74
+
75
+ f_035 = add_f_035(mms_id, hash)
76
+ tind_fields << f_035 if f_035
77
+
78
+ tind_fields
79
+ end
80
+
81
+ def tind_record(id, marc_record, datafields)
82
+ return nil unless Util.collection_config_correct?
83
+
84
+ tindmarc = TindMarc.new(marc_record)
85
+ # get all derived tind_fields: 1) from collection information; 2) from id
86
+ mms_id = tindmarc.field_catalog.mms_id
87
+ logger.warn("#{id} has no Control Field 001") unless mms_id
88
+
89
+ tind_fields = derived_tind_fields(mms_id)
90
+ # add inputted record specific datafields
91
+ tind_fields.concat datafields
92
+ tindmarc.tind_external_datafields = tind_fields
93
+
94
+ # creete a tind marc record
95
+ tindmarc.tind_record
96
+ end
97
+
98
+ def add_f_035(mms_id, hash)
99
+ return nil unless mms_id && AlmaBase.is_035_from_mms_id
100
+
101
+ val_980 = hash['980'][0].strip
102
+ TindField.f_035_from_alma_id(mms_id, val_980)
103
+ end
104
+
105
+ end
106
+ end
107
+ end
108
+ 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,order,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","6,a,e","a,b,c,d,q",a,,,,,,,,"1,_",,,,,
3
+ 110,710,"6,e","6,e","6,a,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","6,a,b,p","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","6,a,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","6,a,e","a,b,c,d,q",a,,,,,,,,"1,_",,,,,
34
+ 710,710,"6,e","6,e","6,a,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