Skip to content

Commit

Permalink
Merge pull request #2439 from sul-dlss/bound-with-holdings
Browse files Browse the repository at this point in the history
Retrieve + display bound-with information
  • Loading branch information
cbeer authored Jun 10, 2024
2 parents 11383a7 + 38592d2 commit 85a2695
Show file tree
Hide file tree
Showing 8 changed files with 934 additions and 522 deletions.
4 changes: 4 additions & 0 deletions app/assets/stylesheets/application_redesign.scss
Original file line number Diff line number Diff line change
Expand Up @@ -325,3 +325,7 @@ label.btn-close {
}
}
}

.status.availability {
text-wrap: nowrap;
}
36 changes: 36 additions & 0 deletions app/models/folio/holdings_record.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# frozen_string_literal: true

module Folio
# Represents a holdings record in Folio.
class HoldingsRecord
attr_reader :id, :call_number, :instance, :items

def initialize(call_number:, id: nil, instance: nil, bound_with_item: nil, items: [], suppressed_from_discovery: false) # rubocop:disable Metrics/ParameterLists
@id = id
@call_number = call_number
@instance = instance
@bound_with_item = bound_with_item
@suppressed_from_discovery = suppressed_from_discovery
@items = items
end

def bound_with_item
@bound_with_item&.with_bound_with_child_holdings_record(self)
end

def suppressed_from_discovery?
@suppressed_from_discovery
end

def self.from_hash(hash)
new(
id: hash['id'],
call_number: hash.fetch('callNumber'),
instance: (Folio::Instance.from_dynamic(hash.fetch('instance')) if hash['instance']),
bound_with_item: (Folio::Item.from_hash(hash.fetch('boundWithItem')) if hash['boundWithItem']),
items: hash.fetch('items', []).map { |item| Folio::Item.from_hash(item.reverse_merge('holdingsRecord' => hash)) },
suppressed_from_discovery: hash['discoverySuppress']
)
end
end
end
18 changes: 14 additions & 4 deletions app/models/folio/instance.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,14 @@ def self.from_dynamic(json)
end,
electronic_access: json.fetch('electronicAccess', []),
edition: json.fetch('editions', []),
items: json.fetch('items', []).map { |item| Folio::Item.from_hash(item) }
holdings_records: json.fetch('holdingsRecords', []).map { |hr| Folio::HoldingsRecord.from_hash(hr) }
)
end
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize

# rubocop:disable Metrics/MethodLength, Metrics/ParameterLists
def initialize(id:, hrid: '', title: '', contributors: [], pub_date: nil, pub_place: nil, publisher: nil, format: nil,
isbn: [], oclcn: [], electronic_access: [], edition: [], items: [])
isbn: [], oclcn: [], electronic_access: [], edition: [], holdings_records: [])
@id = id
@hrid = hrid
@title = title
Expand All @@ -51,7 +51,7 @@ def initialize(id:, hrid: '', title: '', contributors: [], pub_date: nil, pub_pl
@oclcn = oclcn
@electronic_access = electronic_access
@edition = edition
@items = items
@holdings_records = holdings_records
end
# rubocop:enable Metrics/MethodLength, Metrics/ParameterLists

Expand Down Expand Up @@ -95,7 +95,17 @@ def request_holdings(request)
end

def items
@items.reject(&:suppressed_from_discovery?)
@items ||= begin
actual_items = holdings_records.flat_map(&:items)
actual_items_ids = actual_items.map(&:id)
bound_with_items = holdings_records.filter_map(&:bound_with_item).reject { |x| x.id.in? actual_items_ids }

(actual_items + bound_with_items).reject(&:suppressed_from_discovery?)
end
end

def holdings_records
@holdings_records.reject(&:suppressed_from_discovery?)
end

def holdings
Expand Down
18 changes: 16 additions & 2 deletions app/models/folio/item.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ module Folio
# NOTE, barcode and callnumber may be nil. see instance_hrid: 'in00000063826'
class Item
attr_reader :id, :barcode, :status, :type, :public_note, :effective_location, :permanent_location, :temporary_location,
:material_type, :loan_type, :holdings_record_id, :enumeration, :base_callnumber, :full_enumeration, :queue_length
:material_type, :loan_type, :holdings_record_id, :enumeration, :base_callnumber, :full_enumeration, :queue_length,
:instance, :bound_with_holdings_per_item, :bound_with_child_holdings_record

# Other statuses that we aren't using include "Unavailable" and "Intellectual item"
STATUS_CHECKED_OUT = 'Checked out'
Expand Down Expand Up @@ -65,7 +66,7 @@ def initialize(barcode:, status:,
type: nil, public_note: nil, material_type: nil, loan_type: nil, enumeration: nil,
full_enumeration: nil,
due_date: nil, id: nil, holdings_record_id: nil, suppressed_from_discovery: false,
base_callnumber: nil, queue_length: 0)
base_callnumber: nil, queue_length: 0, instance: nil, bound_with_holdings_per_item: [])
@id = id
@holdings_record_id = holdings_record_id
@barcode = barcode.presence || id
Expand All @@ -83,13 +84,20 @@ def initialize(barcode:, status:,
@due_date = due_date
@queue_length = queue_length
@suppressed_from_discovery = suppressed_from_discovery
@instance = instance
@bound_with_holdings_per_item = bound_with_holdings_per_item
end
# rubocop:enable Metrics/ParameterLists, Metrics/MethodLength, Metrics/AbcSize

def with_status(status)
Folio::ItemWithStatus.new(self).with_status(status)
end

def with_bound_with_child_holdings_record(holdings_record)
@bound_with_child_holdings_record = holdings_record
self
end

# TODO: rename this to 'permanent_location_code' after migration
def home_location
permanent_location.code
Expand Down Expand Up @@ -210,6 +218,12 @@ def self.from_hash(dyn)
status: dyn.dig('status', 'name'),
due_date: dyn['dueDate'],
enumeration: dyn['enumeration'],
instance: (Folio::Instance.from_dynamic(dyn['instance']) if dyn['instance']),
bound_with_holdings_per_item: dyn['boundWithHoldingsPerItem']&.filter_map do |v|
next if v['id'].present? && v['id'] == dyn.dig('holdingsRecord', 'id')

Folio::HoldingsRecord.from_hash(v)
end || [],
base_callnumber: dyn.dig('effectiveCallNumberComponents', 'callNumber'),
type: dyn.dig('materialType', 'name'),
full_enumeration: [dyn['volume'], dyn['enumeration'],
Expand Down
210 changes: 123 additions & 87 deletions app/services/folio_graphql_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -102,103 +102,35 @@ def instance(hrid:)
materialsSpecification
uri
}
items {
holdingsRecords {
id
barcode
callNumber
discoverySuppress
volume
queueTotalLength
status {
name
}
queueTotalLength
dueDate
materialType {
id
name
}
chronology
enumeration
effectiveCallNumberComponents {
callNumber
}
notes {
note
itemNoteType {
name
}
}
effectiveLocation {
id
campusId
libraryId
institutionId
code
discoveryDisplayName
name
servicePoints {
id
code
pickupLocation
}
library {
id
code
}
campus {
boundWithItem {
#{item_fields}
instance {
id
code
}
details {
pageAeonSite
pageMediationGroupKey
pageServicePoints {
id
code
hrid
title
instanceType {
name
}
scanServicePointCode
availabilityClass
searchworksTreatTemporaryLocationAsPermanentLocation
}
}
permanentLocation {
id
code
details {
pageAeonSite
pageMediationGroupKey
pageServicePoints {
id
code
name
}
pagingSchedule
scanServicePointCode
}
}
temporaryLocation {
id
code
discoveryDisplayName
}
permanentLoanTypeId
temporaryLoanTypeId
holdingsRecord {
id
effectiveLocation {
items {
#{item_fields}
boundWithHoldingsPerItem {
id
code
details {
pageAeonSite
pageMediationGroupKey
pageServicePoints {
id
code
callNumber
instance {
id
title
hrid
instanceType {
name
}
pagingSchedule
scanServicePointCode
}
}
}
Expand Down Expand Up @@ -237,7 +169,111 @@ def service_points

data&.dig('data', 'servicePoints')
end

# rubocop:enable Metrics/MethodLength
def item_fields
<<-GQL
id
barcode
discoverySuppress
volume
queueTotalLength
status {
name
}
queueTotalLength
dueDate
materialType {
id
name
}
chronology
enumeration
effectiveCallNumberComponents {
callNumber
}
notes {
note
itemNoteType {
name
}
}
effectiveLocation {
id
campusId
libraryId
institutionId
code
discoveryDisplayName
name
servicePoints {
id
code
pickupLocation
}
library {
id
code
}
campus {
id
code
}
details {
pageAeonSite
pageMediationGroupKey
pageServicePoints {
id
code
name
}
scanServicePointCode
availabilityClass
searchworksTreatTemporaryLocationAsPermanentLocation
}
}
permanentLocation {
id
code
details {
pageAeonSite
pageMediationGroupKey
pageServicePoints {
id
code
name
}
pagingSchedule
scanServicePointCode
}
}
temporaryLocation {
id
code
discoveryDisplayName
}
permanentLoanTypeId
temporaryLoanTypeId
holdingsRecord {
id
effectiveLocation {
id
code
details {
pageAeonSite
pageMediationGroupKey
pageServicePoints {
id
code
name
}
pagingSchedule
scanServicePointCode
}
}
}
GQL
end

def ping
# Every GraphQL server supports the trivial query that asks for the "type name" of the top-level query
Expand Down
Loading

0 comments on commit 85a2695

Please sign in to comment.