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

pulibrary / orangelight / ece109aa-ffef-47c6-8f36-d11035b4d00e

07 Nov 2025 10:11PM UTC coverage: 95.413% (+0.003%) from 95.41%
ece109aa-ffef-47c6-8f36-d11035b4d00e

Pull #5343

circleci

Ryan Laddusaw
Rubocop
Pull Request #5343: Add tests for each user group

45 of 45 new or added lines in 10 files covered. (100.0%)

11 existing lines in 1 file now uncovered.

6198 of 6496 relevant lines covered (95.41%)

1465.72 hits per line

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

90.91
/app/helpers/requests/application_helper.rb
1
# frozen_string_literal: true
2
# rubocop:disable Metrics/ModuleLength
3
module Requests
3✔
4
  module ApplicationHelper
3✔
5
    def format_label(key)
3✔
6
      label = key.to_s
×
7
      human_label = label.tr('_', ' ')
×
8
      formatted = human_label.split.map(&:capitalize).join(' ')
×
9
      formatted
×
10
    end
11

12
    def error_key_format(key)
3✔
13
      keys_to_ignore = ['items']
×
14
      format_label(key) unless keys_to_ignore.include? key.to_s
×
15
    end
16

17
    # array of error_keys
18
    def guest_user_error?(error_keys)
3✔
19
      user_errors = [:email, :user_name, :barcode]
×
20
      error_keys.any? { |item| user_errors.include? item }
×
21
    end
22

23
    def show_pick_up_service_options(requestable, mfhd_id)
3✔
24
      if requestable.on_shelf?
135✔
25
        display_on_shelf(requestable, mfhd_id)
70✔
26
      else
27
        display_requestable_list(requestable)
65✔
28
      end
29
    end
30

31
    # :reek:FeatureEnvy
32
    def show_service_options(requestable, _mfhd_id)
3✔
33
      if requestable.charged? && !requestable.aeon? && !requestable.ask_me?
3✔
34
        render partial: 'checked_out_options', locals: { requestable: }
1✔
35
      else
36
        display_requestable_list(requestable)
2✔
37
      end
38
    end
39

40
    def hidden_service_options(requestable, fill_in: false)
3✔
41
      return hidden_service_options_fill_in(requestable) if fill_in
127✔
42
      hidden = output_request_input(requestable)
115✔
43
      return hidden if hidden.present?
115✔
44

45
      if requestable.services.include? 'recap'
44✔
46
        recap_print_only_input requestable
35✔
47
      else
48
        request_input(requestable.services.first)
9✔
49
      end
50
    end
51

52
    def output_request_input(requestable)
3✔
53
      output = ""
115✔
54
      ['annex', 'pres', 'ppl', 'lewis', 'paging', 'on_order', 'on_shelf'].each do |type|
115✔
55
        next unless requestable.services.include?(type)
751✔
56
        output = request_input(type)
71✔
57
        break
71✔
58
      end
59
      output
115✔
60
    end
61

62
    # only requestable services that support "user-supplied volume info"
63
    def hidden_service_options_fill_in(requestable)
3✔
64
      if requestable.annex?
12✔
65
        request_input('annex')
3✔
66
      elsif requestable.services.include? 'recap_no_items'
9✔
67
        request_input('recap_no_items')
1✔
68
      else
69
        request_input('paging')
8✔
70
      end
71
    end
72

73
    def recap_print_only_input(requestable)
3✔
74
      content_tag(:fieldset, class: 'recap--print', id: "recap_group_#{requestable.preferred_request_id}") do
35✔
75
        concat hidden_field_tag "requestable[][type]", "", value: 'recap'
35✔
76
      end
77
    end
78

79
    # rubocop:disable Style/NumericPredicate
80
    def enum_copy_display(item)
3✔
81
      return "" if item.blank?
521✔
82
      [item.description, item.copy_value].join(" ").strip
519✔
83
    end
84
    # rubocop:enable Style/NumericPredicate
85

86
    def request_input(type)
3✔
87
      hidden_field_tag "requestable[][type]", "", value: type
98✔
88
    end
89

90
    def gfa_lookup(lib_code)
3✔
91
      if lib_code == "firestone"
6✔
92
        "PA"
×
93
      else
94
        lib = Requests::BibdataService.delivery_locations.select { |_key, hash| hash["library"]["code"] == lib_code }
144✔
95
        lib.keys.first.to_s
6✔
96
      end
97
    end
98

99
    def pick_up_classlist(requestable, collapse)
3✔
100
      class_list = "collapse request--print"
144✔
101
      class_list += " show" if !requestable.digitize? && !collapse
144✔
102
      class_list
144✔
103
    end
104

105
    # move this to requestable object
106
    # Default pick-ups should be available
107
    def pick_up_choices(requestable, default_pick_ups, collapse = false)
3✔
108
      content_tag(:div, id: "fields-print__#{requestable.preferred_request_id}", class: pick_up_classlist(requestable, collapse)) do
133✔
109
        preferred_request_content_tag(requestable, requestable.pick_up_locations || default_pick_ups)
133✔
110
      end
111
    end
112

113
    # :reek:NilCheck
114
    def preferred_request_content_tag(requestable, default_pick_ups)
3✔
115
      (show_pick_up_service_options(requestable, nil) || "".html_safe) +
138✔
116
        content_tag(:div, id: "fields-print__#{requestable.preferred_request_id}_card", class: "card card-body bg-light") do
117
          locs = pick_up_locations(requestable, default_pick_ups)
138✔
118

119
          name = 'requestable[][pick_up]'
138✔
120
          id = "requestable__pick_up_#{requestable.preferred_request_id}"
138✔
121
          if locs.size > 1
138✔
122
            prompt_text = custom_pickup_prompt(requestable, locs) || I18n.t("requests.default.pick_up_placeholder")
58✔
123
            selected_value = find_selected_pickup_value(requestable, locs)
58✔
124
            # For ReCAP items, select the empty prompt instead of any actual option
125
            selected_value = '' if requestable.recap? && selected_value.nil?
58✔
126
            options = [[prompt_text, '', { disabled: true, selected: false }]] + locs.map { |loc| [loc[:label], { 'pick_up' => loc[:gfa_pickup], 'pick_up_location_code' => loc[:pick_up_location_code] }.to_json] }
540✔
127
            select_tag name.to_s, options_for_select(options, selected_value), id: id
58✔
128
          else
129

130
            single_pickup(requestable.charged?, name, id, locs[0])
80✔
131
          end
132
        end
133
    end
134

135
    # rubocop:disable Rails/OutputSafety
136
    def hidden_fields_mfhd(mfhd)
3✔
137
      hidden = ""
75✔
138
      return hidden if mfhd.nil?
75✔
139
      hidden += hidden_field_tag "mfhd[][call_number]", "", value: (mfhd['call_number']).to_s unless mfhd["call_number"].nil?
74✔
140
      hidden += hidden_field_tag "mfhd[][location]", "", value: (mfhd['location']).to_s unless mfhd["location"].nil?
74✔
141
      hidden += hidden_field_tag "mfhd[][library]", "", value: (mfhd['library']).to_s
74✔
142
      hidden.html_safe
74✔
143
    end
144
    # rubocop:enable Rails/OutputSafety
145

146
    def hidden_fields_item(requestable)
3✔
147
      request_id = requestable.preferred_request_id
527✔
148
      hidden = hidden_field_tag "requestable[][bibid]", "", value: requestable.bib[:id].to_s, id: "requestable_bibid_#{request_id}"
527✔
149
      hidden += hidden_field_tag "requestable[][mfhd]", "", value: requestable.holding.mfhd_id, id: "requestable_mfhd_#{request_id}"
527✔
150
      hidden += hidden_field_tag "requestable[][call_number]", "", value: requestable.holding.holding_data['call_number'].to_s, id: "requestable_call_number_#{request_id}" unless requestable.holding.holding_data["call_number"].nil?
527✔
151
      hidden += hidden_field_tag "requestable[][location_code]", "", value: requestable.item_location_code.to_s, id: "requestable_location_#{request_id}"
527✔
152
      hidden += if requestable.item?
527✔
153
                  hidden_fields_for_item(item: requestable.item, preferred_request_id: requestable.preferred_request_id)
513✔
154
                else
155
                  hidden_field_tag("requestable[][item_id]", "", value: requestable.preferred_request_id, id: "requestable_item_id_#{requestable.preferred_request_id}")
14✔
156
                end
157
      hidden += hidden_fields_for_scsb(item: requestable.item) if requestable.partner_holding?
527✔
158
      hidden
527✔
159
    end
160

161
    def suppress_login?(request)
3✔
162
      request.only_aeon?
79✔
163
    end
164

165
    def item_checkbox(requestable, single_item_form)
3✔
166
      disabled = !requestable.will_submit_via_form?
507✔
167
      check_box_tag "requestable[][selected]", true, check_box_selected?(disabled, single_item_form), class: 'request--select', disabled:, aria: { labelledby: "title enum_#{requestable.preferred_request_id}" }, id: "requestable_selected_#{requestable.preferred_request_id}"
507✔
168
    end
169

170
    ## If any requestable items have a temp location assume everything at the holding is in a temp loc?
171
    def current_location_label(holding_location_label, requestable_list)
3✔
172
      first_location = requestable_list.first.location
147✔
173
      location_label = first_location.short_label.blank? ? "" : "- #{first_location.short_label}"
147✔
174
      label = if requestable_list.first.temp_loc_other_than_resource_sharing?
147✔
175
                "#{first_location.library_label}#{location_label}"
4✔
176
              else
177
                holding_location_label
143✔
178
              end
179
      "#{label} #{requestable_list.first.call_number}"
147✔
180
    end
181

182
    def check_box_selected?(disabled, single_item_form)
3✔
183
      if single_item_form
507✔
184
        !disabled
41✔
185
      else
186
        false
466✔
187
      end
188
    end
189

190
    def submit_button_disabled?(requestable_list)
3✔
191
      # temporary chane issue 438 guest can no longer check out materials
192
      return true if @user.blank? || @user.guest
52✔
193
      return unsubmittable? requestable_list unless requestable_list.size == 1
50✔
194
      # temporary changes issue 438 do not disable the button for circulating items
195
      # requestable_list.first.services.empty? || requestable_list.first.on_reserve? || (requestable_list.first.services.include? 'on_shelf') || requestable_list.first.ask_me?
196
      requestable_list.first.services.empty? || requestable_list.first.on_reserve?
42✔
197
    end
198

199
    def unsubmittable?(requestable_list)
3✔
200
      !requestable_list.any? { |requestable| (requestable.services | submitable_services).present? }
16✔
201
    end
202

203
    def submitable_services
3✔
204
      ['on_shelf', 'in_process', 'on_order', 'annex', 'recap', 'recap_edd', 'paging', 'recap_no_items', 'ppl', 'lewis']
8✔
205
    end
206

207
    def submit_message(requestable_list)
3✔
208
      single_item = "Request this Item"
48✔
209
      multi_item = "Request Selected Items"
48✔
210
      no_item = "No Items Available"
48✔
211
      return multi_item unless requestable_list.size == 1
48✔
212
      if requestable_list.first.services.empty?
40✔
UNCOV
213
        no_item
×
214
      elsif requestable_list.first.annex?
40✔
215
        # Annex items have the potential to display the
216
        # use the fill-in form, where a user could potentially
217
        # request multiple volumes.  For that reason, we show
218
        # the plural form "Request Selected Items" in this case
219
        multi_item
3✔
220
      else
221
        single_item
37✔
222
      end
223
    end
224

225
    # only show the table sort if there are enough items
226
    # to make it worthwhile
227
    def show_tablesorter(requestable_list)
3✔
228
      return "tablesorter" if table_sorter_present?(requestable_list)
74✔
229
      ""
66✔
230
    end
231

232
    def table_sorter_present?(requestable_list)
3✔
233
      requestable_list.size > 5
110✔
234
    end
235

236
    def display_label
3✔
237
      {
×
238
        author: "Author/Artist",
239
        title: "Title",
240
        date: "Published/Created",
241
        id: "Bibliographic ID",
242
        mfhd: "Holding ID (mfhd)"
243
      }.with_indifferent_access
244
    end
245

246
    def display_status(requestable)
3✔
UNCOV
247
      content_tag(:span, requestable.item['status']) unless requestable.item.nil?
×
248
    end
249

250
    def system_status_label(requestable)
3✔
UNCOV
251
      return "" if requestable.item.blank?
×
UNCOV
252
      content_tag(:div, requestable.item[:status], class: 'system-status')
×
253
    end
254

255
    def display_urls(requestable)
3✔
UNCOV
256
      content_tag :ol do
×
UNCOV
257
        requestable.urls.each do |key, value|
×
UNCOV
258
          unless key == 'iiif_manifest_paths'
×
UNCOV
259
            value.reverse!
×
UNCOV
260
            concat content_tag(:li, link_to(value.join(": "), key), class: 'link')
×
261
          end
262
        end
263
      end
264
    end
265

266
    def self.recap_annex_available_pick_ups(requestable, default_pick_ups)
3✔
267
      locations = requestable.pick_up_locations || default_pick_ups
59✔
268
      pick_ups = locations.select { |loc| Requests::Location.valid_recap_annex_pickup?(loc) }
667✔
269
      pick_ups << default_pick_ups[0] if pick_ups.empty?
59✔
270
      pick_ups
59✔
271
    end
272

273
    private
3✔
274

275
      def custom_pickup_prompt(requestable, locs)
3✔
276
        # For ReCAP items, return nil to use default prompt
277
        return nil if requestable.recap?
65✔
278

279
        holding_library = normalize_holding_library(requestable)
25✔
280
        return nil if holding_library.blank?
25✔
281

282
        find_prompt_for_holding_library(holding_library, locs)
25✔
283
      end
284

285
      # :reek:UtilityFunction
286
      def normalize_holding_library(requestable)
3✔
287
        requestable.holding_library&.downcase
43✔
288
      end
289

290
      def find_prompt_for_holding_library(holding_library, locs)
3✔
291
        # Check for special engineering library cases first
292
        engineering_prompt = engineering_library_prompt(holding_library, locs)
25✔
293
        return engineering_prompt if engineering_prompt
25✔
294

295
        # Find matching library by code and suggest it in the prompt
296
        suggested_location = find_matching_location_label(holding_library, locs)
21✔
297
        return unless suggested_location
21✔
298
        I18n.t('requests.pick_up_suggested.holding_library', holding_library: suggested_location)
4✔
299
        # "Select a Delivery Location (Recommended: #{suggested_location})"
300
      end
301

302
      def find_matching_location_label(holding_library, locs)
3✔
303
        matching_loc = find_matching_location_by_code(holding_library, locs)
21✔
304
        matching_loc&.dig(:label)
21✔
305
      end
306

307
      # :reek:UtilityFunction
308
      def find_matching_location_by_code(holding_library, locs)
3✔
309
        locs.find do |loc|
37✔
310
          # Extract library code and compare with holding library
311
          location = Requests::Location.new(loc)
189✔
312
          location.library_code&.downcase == holding_library
189✔
313
        end
314
      end
315

316
      # :reek:UtilityFunction
317
      def engineering_library_prompt(holding_library, locs)
3✔
318
        # Special case: lewis, plasma should default to Engineering Library
319
        if ['lewis', 'plasma'].include?(holding_library)
25✔
320
          engineering_loc = locs.find { |loc| loc[:label] == "Engineering Library" }
16✔
321
          return I18n.t('requests.pick_up_suggested.engineering_holding_library', engineering_holding_library: engineering_loc[:label]) if engineering_loc
5✔
322
        end
323
        nil
21✔
324
      end
325

326
      def find_selected_pickup_value(requestable, locs)
3✔
327
        return nil if should_skip_form_preselection?(requestable)
58✔
328

329
        holding_library = normalize_holding_library(requestable)
18✔
330
        return nil if holding_library.blank?
18✔
331

332
        find_form_preselected_location_json(holding_library, locs)
18✔
333
      end
334

335
      # :reek:UtilityFunction
336
      def should_skip_form_preselection?(requestable)
3✔
337
        requestable.recap?
58✔
338
      end
339

340
      def find_form_preselected_location_json(holding_library, locs)
3✔
341
        selected_location = find_engineering_location(holding_library, locs) ||
18✔
342
                            find_matching_location_by_code(holding_library, locs)
343
        return nil unless selected_location
18✔
344

345
        location_to_json(selected_location)
3✔
346
      end
347

348
      # :reek:UtilityFunction
349
      def find_engineering_location(holding_library, locs)
3✔
350
        return nil unless ['lewis', 'plasma'].include?(holding_library)
18✔
351
        locs.find { |loc| Requests::Location.new(loc).engineering_library? }
6✔
352
      end
353

354
      # :reek:UtilityFunction
355
      def location_to_json(location)
3✔
356
        { 'pick_up' => location[:gfa_pickup], 'pick_up_location_code' => location[:pick_up_location_code] }.to_json
3✔
357
      end
358

359
      def display_requestable_list(requestable)
3✔
360
        content_tag(:ul, class: "service-list") do
137✔
361
          if requestable.ill_eligible?
137✔
362
            concat content_tag(:li, sanitize(I18n.t("requests.ill.brief_msg")), class: "service-item")
1✔
363
          else
364
            # there are no instances where more than one actual service is available to an item, so we are going to take the first service that is not edd
365
            filtered_services = if requestable.services.size == 1 && requestable.services.first.include?("edd")
136✔
UNCOV
366
                                  requestable.services
×
367
                                else
368
                                  requestable.services.reject { |service_name| service_name.include?("edd") }
385✔
369
                                end
370
            # if there is not a valid service this will evaluate to `requests.brief_msg` and display an error message.
371
            brief_msg = if filtered_services.first
136✔
372
                          I18n.t("requests.#{filtered_services.first}.brief_msg")
134✔
373
                        else
374
                          I18n.t("requests.alma_login.no_access")
2✔
375
                        end
376
            concat content_tag(:li, sanitize(brief_msg), class: "service-item")
136✔
377
          end
378
        end
379
      end
380

381
      def display_on_shelf(requestable, _mfhd_id)
3✔
382
        content_tag(:div) do
70✔
383
          display_requestable_list(requestable)
70✔
384
        end
385
      end
386

387
      def pick_up_locations(requestable, default_pick_ups)
3✔
388
        # we don't want to change the ill_eligible rules
389
        return ill_eligible_pick_up_location(default_pick_ups) if requestable.ill_eligible?
140✔
390
        return Requests::ApplicationHelper.recap_annex_available_pick_ups(requestable, default_pick_ups) if requestable.recap? || requestable.annex?
138✔
391
        return default_pick_ups if requestable.location&.standard_circ_location?
82✔
392
        if requestable.delivery_location_label.present?
79✔
393
          [{ label: requestable.delivery_location_label, gfa_pickup: requestable.delivery_location_code, pick_up_location_code: requestable.pick_up_location_code, staff_only: false }]
72✔
394
        else
395
          [{ label: requestable.location.library_label, gfa_pickup: gfa_lookup(requestable.location.library_code), staff_only: false }]
7✔
396
        end
397
      end
398

399
      # :reek:UtilityFunction
400
      def ill_eligible_pick_up_location(default_pick_ups)
3✔
401
        # currently for resource sharing items through Illiad we use firestone Library with gfa_pickup of PA
402
        location = default_pick_ups.find { |location| location[:gfa_pickup] == "PA" }
7✔
403
        [location].compact
2✔
404
      end
405

406
      def hidden_fields_for_item(item:, preferred_request_id:)
3✔
407
        hidden = hidden_field_tag("requestable[][item_id]", "", value: preferred_request_id.to_s, id: "requestable_item_id_#{preferred_request_id}")
513✔
408
        hidden += hidden_field_tag("requestable[][barcode]", "", value: item['barcode'].to_s, id: "requestable_barcode_#{preferred_request_id}") unless item["barcode"].nil?
513✔
409
        hidden += hidden_field_tag("requestable[][enum]", "", value: item.enum_value.to_s, id: "requestable_enum_#{preferred_request_id}") if item.enum_value.present?
513✔
410
        hidden += hidden_field_tag("requestable[][copy_number]", "", value: item.copy_number.to_s, id: "requestable_copy_number_#{preferred_request_id}")
513✔
411
        hidden + hidden_field_tag("requestable[][status]", "", value: item['status'].to_s, id: "requestable_status_#{preferred_request_id}")
513✔
412
      end
413

414
      def hidden_fields_for_scsb(item:)
3✔
415
        hidden = hidden_field_tag("requestable[][cgd]", "", value: item['cgd'].to_s, id: "requestable_cgd_#{item['id']}")
6✔
416
        hidden += hidden_field_tag("requestable[][cc]", "", value: item['collection_code'].to_s, id: "requestable_collection_code_#{item['id']}")
6✔
417
        hidden + hidden_field_tag("requestable[][use_statement]", "", value: item['use_statement'].to_s, id: "requestable_use_statement_#{item['id']}")
6✔
418
      end
419

420
      def single_pickup(is_charged, name, id, location)
3✔
421
        style = if is_charged
80✔
UNCOV
422
                  'margin-top:10px;'
×
423
                else
424
                  ''
80✔
425
                end
426
        hidden = hidden_field_tag name.to_s, "", value: { 'pick_up' => location[:gfa_pickup], 'pick_up_location_code' => location[:pick_up_location_code] }.to_json, class: 'single-pick-up-hidden', id: id
80✔
427
        label = label_tag id, "Pick-up location: #{location[:label]}", class: 'single-pick-up', style: style.to_s
80✔
428
        hidden + label
80✔
429
      end
430
  end
431
end
432
# rubocop:enable Metrics/ModuleLength
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