berkeley_library-tind 0.5.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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