• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pulibrary / orangelight / ebbc87e6-dba7-45c6-a9de-e78e5598b86c

17 Jul 2025 03:58PM UTC coverage: 94.807% (-0.6%) from 95.407%
ebbc87e6-dba7-45c6-a9de-e78e5598b86c

Pull #4962

circleci

christinach
Display only the library name in search results
generate new reek

In the search results availability should only display the Library name.
Pull Request #4962: Orangelight pos workcycle 07-07-2025

61 of 102 new or added lines in 10 files covered. (59.8%)

1 existing line in 1 file now uncovered.

6061 of 6393 relevant lines covered (94.81%)

1503.59 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

49.38
/app/services/physical_holdings_markup_builder.rb
1
# frozen_string_literal: false
2

3
class PhysicalHoldingsMarkupBuilder < HoldingRequestsBuilder
3✔
4
  include ApplicationHelper
3✔
5

6
  def holding_location_repository
3✔
NEW
7
    children = content_tag(:span,
×
8
                           'On-site access',
9
                           class: 'availability-icon badge bg-success')
NEW
10
    content_tag(:td, children.html_safe)
×
11
  end
12

13
  # Holding record with "dspace": false
14
  def holding_location_unavailable
3✔
NEW
15
    children = content_tag(:span,
×
16
                           'Unavailable',
17
                           class: 'availability-icon badge bg-danger')
NEW
18
    content_tag(:td, children.html_safe, class: 'holding-status')
×
19
  end
20

21
  def self.open_location?(location)
3✔
NEW
22
    location.nil? ? false : location[:open]
×
23
  end
24

25
  def self.requestable_location?(location, adapter, holding)
3✔
NEW
26
    return false if adapter.sc_location_with_suppressed_button?(holding)
×
NEW
27
    if location.nil?
×
NEW
28
      false
×
NEW
29
    elsif adapter.unavailable_holding?(holding)
×
NEW
30
      false
×
31
    else
NEW
32
      location[:requestable]
×
33
    end
34
  end
35

36
  def self.aeon_location?(location)
3✔
NEW
37
    location.nil? ? false : location[:aeon_location]
×
38
  end
39

40
  delegate :aeon_location?, to: :class
3✔
41

42
  def self.scsb_location?(location)
3✔
NEW
43
    location.nil? ? false : /^scsb.+/ =~ location['code']
×
44
  end
45

46
  def self.requestable?(adapter, holding_id, location)
3✔
NEW
47
    !adapter.alma_holding?(holding_id) || aeon_location?(location) || scsb_location?(location)
×
48
  end
49

50
  def self.thesis?(adapter, holding_id)
3✔
NEW
51
    holding_id == 'thesis' && adapter.pub_date > 2012
×
52
  end
53

54
  def self.numismatics?(holding_id)
3✔
NEW
55
    holding_id == 'numismatics'
×
56
  end
57

58
  # Generate the CSS class for holding based upon its location and ID
59
  # @param adapter [HoldingRequestsAdapter] adapter for the Solr Document and Bibdata
60
  # @param location [Hash] location information
61
  # @param holding_id [String]
62
  # @return [String] the CSS class
63
  def self.show_request(adapter, location, holding_id)
3✔
NEW
64
    if requestable?(adapter, holding_id, location) && !thesis?(adapter, holding_id) || numismatics?(holding_id)
×
NEW
65
      'service-always-requestable'
×
66
    else
NEW
67
      'service-conditional'
×
68
    end
69
  end
70

71
  # Generate the location services markup for a holding
72
  # @param adapter [HoldingRequestsAdapter] adapter for the Solr Document and Bibdata
73
  # @param holding_id [String]
74
  # @param location_rules [Hash]
75
  # @param link [String] link markup
76
  # @return [String] block markup
77
  def self.location_services_block(adapter, holding_id, location_rules, link, holding)
3✔
NEW
78
    content_tag(:td, link,
×
79
                class: "location-services #{show_request(adapter, location_rules, holding_id)}",
80
                data: {
81
                  open: open_location?(location_rules),
82
                  requestable: requestable_location?(location_rules, adapter, holding),
83
                  aeon: aeon_location?(location_rules),
84
                  holding_id:
85
                })
86
  end
87

88
  def doc_id(holding)
3✔
NEW
89
    holding.dig("mms_id") || adapter.doc_id
×
90
  end
91

92
  # Example of a temporary holding, in this case holding_id is : firestone$res3hr
93
  # {\"firestone$res3hr\":{\"location_code\":\"firestone$res3hr\",
94
  # \"current_location\":\"Circulation Desk (3 Hour Reserve)\",\"current_library\":\"Firestone Library\",
95
  # \"call_number\":\"HT1077 .M87\",\"call_number_browse\":\"HT1077 .M87\",
96
  # \"items\":[{\"holding_id\":\"22740601020006421\",\"id\":\"23740600990006421\",
97
  # \"status_at_load\":\"1\",\"barcode\":\"32101005621469\",\"copy_number\":\"1\"}]}}
98
  def self.temporary_holding_id?(holding_id)
3✔
NEW
99
    /[a-zA-Z]\$[a-zA-Z]/.match?(holding_id)
×
100
  end
101

102
  # When it is a temporary location and is requestable, use the first holding_id of this temporary location items.
103
  def self.temporary_location_holding_id_first(holding)
3✔
NEW
104
    holding["items"][0]["holding_id"]
×
105
  end
106

107
  # Generate the links for a given holding
108
  # TODO: Come back and remove class method calls
109
  def request_placeholder(adapter, holding_id, location_rules, holding)
3✔
NEW
110
    doc_id = doc_id(holding)
×
NEW
111
    view_base = ActionView::Base.new(ActionView::LookupContext.new([]), {}, nil)
×
NEW
112
    link = request_link_component(adapter:, holding_id:, doc_id:, holding:, location_rules:).render_in(view_base)
×
NEW
113
    markup = self.class.location_services_block(adapter, holding_id, location_rules, link, holding)
×
NEW
114
    markup
×
115
  end
116

117
  def request_link_component(adapter:, holding_id:, doc_id:, holding:, location_rules:)
3✔
NEW
118
    holding_object = Requests::Holding.new(mfhd_id: holding_id, holding_data: holding)
×
NEW
119
    if holding_id == 'thesis' || self.class.numismatics?(holding_id)
×
NEW
120
      AeonRequestButtonComponent.new(document: adapter.document, holding: holding_object.to_h, url_class: Requests::NonAlmaAeonUrl)
×
NEW
121
    elsif holding['items'] && holding['items'].length > 1
×
NEW
122
      RequestButtonComponent.new(doc_id:, holding_id:, location: location_rules)
×
NEW
123
    elsif aeon_location?(location_rules)
×
NEW
124
      AeonRequestButtonComponent.new(document: adapter.document, holding: holding_object.to_h)
×
NEW
125
    elsif self.class.scsb_location?(location_rules)
×
NEW
126
      RequestButtonComponent.new(doc_id:, location: location_rules, holding:)
×
NEW
127
    elsif self.class.temporary_holding_id?(holding_id)
×
NEW
128
      holding_identifier = self.class.temporary_location_holding_id_first(holding)
×
NEW
129
      RequestButtonComponent.new(doc_id:, holding_id: holding_identifier, location: location_rules)
×
130
    else
NEW
131
      RequestButtonComponent.new(doc_id:, holding_id:, location: location_rules)
×
132
    end
133
  end
134

135
  attr_reader :adapter
3✔
136
  delegate :content_tag, :link_to, to: :class
3✔
137

138
  # Constructor
139
  # @param adapter [HoldingRequestsAdapter] adapter for the SolrDocument and Bibdata API
140
  def initialize(adapter)
3✔
141
    @adapter = adapter
108✔
142
  end
143

144
  # Builds the markup for online and physical holdings for a given record
145
  # @return [String] the markup for the online and physical holdings
146
  def build
3✔
147
    physical_holdings_block
108✔
148
  end
149

150
  private
3✔
151

152
    # Generate the markup for physical holdings
153
    # @return [String] the markup
154
    def physical_holdings
3✔
155
      markup = ''
108✔
156
      @adapter.sorted_physical_holdings.each do |holding_id, holding|
108✔
157
        markup << render_component(Holdings::PhysicalHoldingComponent.new(adapter, holding_id, holding))
181✔
158
      end
159
      markup
108✔
160
    end
161

162
    # Generate the markup block for physical holdings
163
    # @return [String] the markup
164
    def physical_holdings_block
3✔
165
      markup = ''
108✔
166
      children = physical_holdings
108✔
167
      markup = self.class.content_tag(:tbody, children.html_safe) unless children.empty?
108✔
168
      markup
108✔
169
    end
170

171
    def render_component(component)
3✔
172
      view_context.render(component)
181✔
173
    end
174

175
    def view_context
3✔
176
      @view_context ||= ApplicationController.new.view_context
181✔
177
    end
178
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc