module Voyager module Holdings class Record attr_reader :holding_id, :location_name, :call_number, :summary_holdings, :notes_852, :notes_866, :notes, :shelving_title, :supplements, :indexes, :reproduction_note, :urls, :item_count, :temp_locations, :item_status, :orders, :current_issues, :services, :bibid # Record class initializing method # Populates instance variables from the mfhd:marcRecord node of the mfhd:mfhdRecord node. # Also instantiates Otem and Order classes for the mfhd:mfhdRecord node. # # * *Args* : # - +xml_node+ -> mfhd:mfhdRecord node # def initialize(xml_node) @bibid = xml_node.attributes["bibId"].value @holding_id = xml_node.attributes["mfhdId"].value @location_name = xml_node.at_css("mfhd|mfhdData[@name='locationDisplayName']").content # marc record node marc = xml_node.at_css("mfhd|marcRecord") # 852 holdings tag node tag852 = marc.at_css("slim|datafield[@tag='852']") # 866 holdings tag node tag866 = marc.css("slim|datafield[@tag='866']") @call_number = parse_call_number(tag852) # string @summary_holdings = parse_summary_holdings(tag866) # array @notes_852 = parse_notes_852(tag852) # array @notes_866 = parse_notes_866(tag866) # array # combine notes into a single array @notes = @notes_852 + @notes_866 # array @shelving_title = parse_shelving_title(tag852) # string @supplements = parse_supplements(marc) # array @indexes = parse_indexes(marc) # array @reproduction_note = parse_reproduction_note(marc) #string @urls = parse_urls(marc) # array of hashes # information from item level records item = Item.new(xml_node) @item_count = item.item_count @temp_locations = item.temp_locations @item_status = item.item_status # special case for single temp location if @item_count == '1' && (not @temp_locations.empty?) # temp location begins 'Shelved in' if it is not for a part if @temp_locations.first.match(/^Shelved/) # remove 'Shelved in' and replace location_name @location_name = @temp_locations.first.gsub(/^Shelved in /, '') @temp_locations.clear end end # set item status for online items if @location_name.match(/^Online/) @item_status[:status] = 'online' @item_status[:messages].clear end # information from order/receipt records order = Order.new(xml_node) @current_issues = order.current_issues @orders = order.orders # add available services @services = determine_services(@location_name,@call_number,@item_status,@orders,@bibid) end # Collect data from all variables into a hash # # * *Returns* : # - Hash # def to_hash { :bibid => @bibid, :holding_id => @holding_id, :location_name => @location_name, :call_number => @call_number, :shelving_title => @shelving_title, :summary_holdings => @summary_holdings, :supplements => @supplements, :indexes => @indexes, :notes => @notes, :reproduction_note => @reproduction_note, :urls => @urls, :item_count => @item_count, :temp_locations => @temp_locations, :item_status => @item_status, :services => @services, :current_issues => @current_issues, :orders => @orders } end private # Extract call number # # * *Args* : # - +tag852+ -> 852 field node; not repeatable # * *Returns* : # - Call number string # def parse_call_number(tag852) g = tag852.at_css("slim|subfield[@code='g']") h = tag852.at_css("slim|subfield[@code='h']") i = tag852.at_css("slim|subfield[@code='i']") k = tag852.at_css("slim|subfield[@code='k']") m = tag852.at_css("slim|subfield[@code='m']") # subfields need to be output in this order even though they may not appear in this order [k,g,h,i,m].compact.collect { |subfield| subfield.content }.join(" ") end # Extract summary holdings from 866 field # # * *Args* : # - +tag866+ -> 866 field node; repeatable # * *Returns* : # - Array of summary holdings statements # - Empty array if there are no summary holdings # def parse_summary_holdings(tag866) return [] unless tag866 summary = tag866.collect do |field| field.at_css("slim|subfield[@code='a']") end summary.compact.collect { |subfield| subfield.content.strip } end # Extract public notes from 852 field, subfield z # # * *Args* : # - +tag852+ -> 852 field node; not repeatable # * *Returns* : # - Array of note statements # - Empty array if there are no notes # def parse_notes_852(tag852) subz = tag852.css("slim|subfield[@code='z']") return [] unless subz # there can be multiple z's subz.collect { |subfield| subfield.content } end # Extract public notes from 866 fields, subfield z # # * *Args* : # - +tag866+ -> 866 field node; repeatable # * *Returns* : # - Array of note statements # - Empty array if there are no notes # def parse_notes_866(tag866) return [] unless tag866 notes = tag866.collect do |field| field.at_css("slim|subfield[@code='z']") end notes.compact.collect { |subfield| subfield.content } end # Extract shelving title # # * *Args* : # - +tag852+ -> 852 field node; not repeatable # * *Returns* : # - Shelving title string # def parse_shelving_title(tag852) subl = tag852.at_css("slim|subfield[@code='l']") subl ? subl.content : '' end # Extract supplement holdings from field 867 # # * *Args* : # - +marc+ -> mfhd:marcRecord node # * *Returns* : # - Array of supplement holdings statements # - Empty array if there are no summary holdings # def parse_supplements(marc) tag867 = marc.css("slim|datafield[@tag='867']") return [] unless tag867 supplements = tag867.collect do |field| field.at_css("slim|subfield[@code='a']") end supplements.compact.collect { |subfield| subfield.content } end # Extract index holdings from field 868 # # * *Args* : # - +marc+ -> mfhd:marcRecord node # * *Returns* : # - Array of index holdings statements # - Empty array if there are no summary holdings # def parse_indexes(marc) tag868 = marc.css("slim|datafield[@tag='868']") return [] unless tag868 indexes = tag868.collect do |field| field.at_css("slim|subfield[@code='a']") end indexes.compact.collect { |subfield| subfield.content } end # Extract reproduction note from field 843 # # * *Args* : # - +marc+ -> mfhd:marcRecord node # * *Returns* : # - Reproduction note string # def parse_reproduction_note(marc) tag843 = marc.at_css("slim|datafield[@tag='843']") return '' unless tag843 # collect subfields in input order; only ouput certain subfields tag843.css("slim|subfield").collect { |subfield| subfield.content if subfield.attr("code").match(/[abcdefmn3]/)}.join(' ') end # Extract URLs from 856 fields in the marc holdings record # # * *Args* : # - +marc+ -> mfhd:marcRecord node # * *Returns* : # - Array of hashes for urls # { :url => url, :link_text => link text } # - Empty array if there are no urls in the holdings record # Note: there may be urls in the bib record. # def parse_urls(marc) tag856 = marc.css("slim|datafield[@tag='856']") return [] unless tag856 urls = [] tag856.each do |field| # only process idicators 40 if field.attr("ind1") == '4' and field.attr("ind2") == '0' subu = field.at_css("slim|subfield[@code='u']") subz = field.at_css("slim|subfield[@code='z']") sub3 = field.at_css("slim|subfield[@code='3']") # only process if there is a url if subu url = subu.content link_text = [sub3, subz].compact.collect { |subfield| subfield.content } if link_text.empty? link_text << url end urls << { :url => url, :link_text => link_text.join(' ') } end end end urls end def determine_services(location_name,call_number,item_status,orders,bibid) services = [] unless orders.empty? orders.each do |order| parms = ORDER_STATUS_CODES[order[:status_code]] raise "Status code not found in config/order_status_codes.yml" unless parms services << parms['services'] unless parms['services'].nil? end return services.flatten.uniq end services << scan_message(location_name) status = item_status[:status] messages = item_status[:messages] case status when 'online' when 'none' services << 'in_process' if call_number.match(/in process/i) when 'available' services << process_available(location_name,bibid) when 'some_available' services << process_some_available(location_name,bibid,messages) when 'not_available' services << scan_messages(messages) else end services.flatten.uniq end def process_available(location_name,bibid) # offsite if location_name.match(/^Offsite/) && HTTPClient.new.get_content("http://www.columbia.edu/cgi-bin/cul/lookupNBX?" + bibid) == "1" return ['offsite'] end # precat if location_name.match(/^Precat/) return ['precat'] end return [] end def process_some_available(location_name,bibid,messages) services = [] # offsite if location_name.match(/^Offsite/) && HTTPClient.new.get_content("http://www.columbia.edu/cgi-bin/cul/lookupNBX?" + bibid) == "1" services << 'offsite' end services << scan_messages(messages) services end def scan_messages(messages) services = [] messages.each do |message| # status patrons if message[:status_code] == 'sp' services << scan_message(message[:long_message]) else parms = ITEM_STATUS_CODES[message[:status_code]] raise "Status code not found in config/order_status_codes.yml" unless parms services << parms['services'] unless parms['services'].nil? end end services end def scan_message(message) out = [] out << 'recall_hold' if message =~ /Recall/i out << 'recall_hold' if message =~ /hold / out << 'borrow_direct' if message =~ /Borrow/ out << 'ill' if message =~ /ILL/ out << 'in_process' if message =~ /In Process/ out end end end end