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

pulibrary / orangelight / 6dd8e2a8-7dce-42ae-878b-86f433262d38

17 Sep 2024 06:20PM UTC coverage: 96.474% (-0.07%) from 96.543%
6dd8e2a8-7dce-42ae-878b-86f433262d38

push

circleci

web-flow
Merge pull request #4353 from pulibrary/requests-form-v5

Remove load_serial_items method

1 of 1 new or added line in 1 file covered. (100.0%)

4 existing lines in 1 file now uncovered.

5964 of 6182 relevant lines covered (96.47%)

1504.97 hits per line

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

97.21
/app/models/requests/form.rb
1
# frozen_string_literal: true
2
require 'faraday'
3✔
3

4
module Requests
3✔
5
  # Request class is responsible of building a request
6
  # using items and location of the holding
7
  class Form
3✔
8
    attr_reader :system_id
3✔
9
    attr_reader :mfhd
3✔
10
    attr_reader :patron
3✔
11
    attr_reader :doc
3✔
12
    attr_reader :requestable
3✔
13
    attr_reader :requestable_unrouted
3✔
14
    attr_reader :holdings
3✔
15
    attr_reader :location
3✔
16
    attr_reader :location_code
3✔
17
    attr_reader :items
3✔
18
    attr_reader :pick_ups
3✔
19
    alias default_pick_ups pick_ups
3✔
20
    delegate :ctx, to: :@ctx_obj
3✔
21
    delegate :eligible_for_library_services?, to: :patron
3✔
22

23
    include Requests::Bibdata
3✔
24
    include Requests::Scsb
3✔
25

26
    # @option opts [String] :system_id A bib record id or a special collection ID value
27
    # @option opts [Fixnum] :mfhd alma holding id
28
    # @option opts [Patron] :patron current Patron object
29
    def initialize(system_id:, mfhd:, patron: nil)
3✔
30
      @system_id = system_id
309✔
31
      @doc = SolrDocument.new(solr_doc(system_id))
309✔
32
      @holdings = JSON.parse(doc[:holdings_1display] || '{}')
309✔
33
      # scsb items are the only ones that come in without a MFHD parameter from the catalog now
34
      # set it for them, because they only ever have one location
35
      @mfhd = mfhd || @holdings.keys.first
309✔
36
      @patron = patron
309✔
37
      @location_code = @holdings[@mfhd]["location_code"] if @holdings[@mfhd].present?
309✔
38
      @location = load_bibdata_location
309✔
39
      @items = load_items
309✔
40
      @pick_ups = build_pick_ups
309✔
41
      @requestable_unrouted = build_requestable
309✔
42
      @requestable = route_requests(@requestable_unrouted)
309✔
43
      @ctx_obj = Requests::SolrOpenUrlContext.new(solr_doc: doc)
309✔
44
    end
45

46
    delegate :user, to: :patron
3✔
47

48
    def requestable?
3✔
49
      requestable.size.positive?
90✔
50
    end
51

52
    def first_filtered_requestable
3✔
53
      requestable&.first
96✔
54
    end
55

56
    # Does this request object have any available copies?
57
    def any_loanable_copies?
3✔
58
      requestable_unrouted.any? do |requestable|
2,346✔
59
        !(requestable.charged? || (requestable.aeon? || !requestable.circulates? || requestable.partner_holding? || requestable.on_reserve?))
25,475✔
60
      end
61
    end
62

63
    def any_enumerated?
3✔
64
      requestable_unrouted.any?(&:enumerated?)
1✔
65
    end
66

67
    def route_requests(requestable_items)
3✔
68
      routed_requests = []
309✔
69
      return [] if requestable_items.blank?
309✔
70
      requestable_items.each do |requestable|
300✔
71
        router = Requests::Router.new(requestable:, user: patron.user, any_loanable: any_loanable_copies?)
2,342✔
72
        routed_requests << router.routed_request
2,342✔
73
      end
74
      routed_requests
300✔
75
    end
76

77
    def serial?
3✔
78
      doc[:format].present? && doc[:format].include?('Journal')
1✔
79
    end
80

81
    def recap?
3✔
82
      return false if location.blank?
275✔
83
      location[:remote_storage] == "recap_rmt"
265✔
84
    end
85

86
    # returns nil if there are no attached items
87
    # if mfhd set returns only items associated with that mfhd
88
    # if no mfhd returns items sorted by mfhd
89
    def load_items
3✔
90
      return nil if too_many_items?
309✔
91
      mfhd_items = load_items_by_mfhd
307✔
92
      mfhd_items.empty? ? nil : mfhd_items.with_indifferent_access
307✔
93
    end
94

95
    # returns basic metadata for hidden fields on the request form via solr_doc values
96
    # Fields to return all keys are arrays
97
    ## Add more fields here as needed
98
    def hidden_field_metadata
3✔
99
      {
100
        title: doc["title_citation_display"],
90✔
101
        author: doc["author_citation_display"],
102
        isbn: doc["isbn_s"]&.values_at(0),
103
        date: doc["pub_date_display"]
104
      }
105
    end
106

107
    # Calls Requests::BibdataService to get the delivery_locations
108

109
    def ill_eligible?
3✔
110
      requestable.any? { |r| r.services.include? 'ill' }
×
111
    end
112

113
    def other_id
3✔
114
      doc['other_id_s'].first
31✔
115
    end
116

117
    def scsb_location
3✔
118
      doc['location_code_s'].first
112✔
119
    end
120

121
    # holdings: The holdings1_display from the SolrDocument
122
    # holding: The holding of the holding_id(mfhd) from the SolrDocument
123
    # happens on 'click' the 'Request' button
124
    def too_many_items?
3✔
125
      holding = holdings[@mfhd]
313✔
126
      items = holding.try(:[], "items")
313✔
127
      return false if items.blank?
313✔
128

129
      return true if items.count > 500
266✔
130

131
      false
264✔
132
    end
133

134
    private
3✔
135

136
      ### builds a list of possible requestable items
137
      # returns a collection of requestable objects or nil
138
      # @return [Array<Requests::Requestable>] array containing Requests::Requestables
139
      def build_requestable
3✔
140
        return [] if doc._source.blank?
309✔
141
        if doc.scsb_record?
307✔
142
          build_scsb_requestable
30✔
143
        elsif items.present?
277✔
144
          # for single aeon item, ends up in this statement
145
          build_requestable_with_items
275✔
146
        else
147
          # for too many aeon items, ends up in this statement
148
          build_requestable_from_data
2✔
149
        end
150
      end
151

152
      def availability_data(id)
3✔
153
        @availability_data ||= items_by_id(id, scsb_owning_institution(scsb_location))
112✔
154
      end
155

156
      # @return [Array<Requests::Requestable>] array containing Requests::Requestables
157
      def build_scsb_requestable
3✔
158
        requestable_items = []
30✔
159
        holdings.each do |id, values|
30✔
160
          requestable_items = build_holding_scsb_items(id:, values:, availability_data: availability_data(other_id), requestable_items:)
30✔
161
        end
162
        requestable_items
30✔
163
      end
164

165
      # @return [Array<Requests::Requestable>] array containing Requests::Requestables
166
      def build_holding_scsb_items(id:, values:, availability_data:, requestable_items:)
3✔
167
        values_items = values['items']
30✔
168
        return requestable_items if values_items.blank?
30✔
169
        barcodesort = build_barcode_sort(items: values_items, availability_data:)
30✔
170
        barcodesort.each_value do |item|
30✔
171
          item['location_code'] = location_code
62✔
172
          params = build_requestable_params(item: item.with_indifferent_access, holding: Holding.new(mfhd_id: id.to_sym.to_s, holding_data: holdings[id]),
62✔
173
                                            location:)
174
          requestable_items << Requests::Requestable.new(**params)
62✔
175
        end
176
        requestable_items
30✔
177
      end
178

179
      def build_barcode_sort(items:, availability_data:)
3✔
180
        barcodesort = {}
112✔
181
        items.each do |item|
112✔
182
          item[:status_label] = status_label(item:, availability_data:)
428✔
183
          barcodesort[item['barcode']] = item
428✔
184
        end
185
        availability_data.each do |item|
112✔
186
          barcode_item = barcodesort[item['itemBarcode']]
74✔
187
          next if barcode_item.blank? || barcode_item["status_source"] == "work_order" || item['errorMessage'].present?
74✔
188
          barcode_item['status_label'] = item['itemAvailabilityStatus']
60✔
189
          barcode_item['status'] = nil
60✔
190
        end
191
        barcodesort
112✔
192
      end
193

194
      # :reek:DuplicateMethodCall
195
      def status_label(item:, availability_data:)
3✔
196
        item_object = Item.new item
428✔
197
        if item_object.not_a_work_order? && availability_data.empty?
428✔
198
          "Unavailable"
315✔
199
        elsif item_object.not_a_work_order? && item_object.status_label == 'Item in place' && availability_data.size == 1 && availability_data.first['errorMessage'] == "Bib Id doesn't exist in SCSB database."
113✔
200
          "In Process"
2✔
201
        else
202
          item_object.status_label
111✔
203
        end
204
      end
205

206
      # @return [Array<Requests::Requestable>] array containing Requests::Requestables
207
      def build_requestable_with_items
3✔
208
        requestable_items = []
275✔
209
        barcodesort = {}
275✔
210
        barcodesort = build_barcode_sort(items: items[mfhd], availability_data: availability_data(system_id)) if recap?
275✔
211
        # items from the availability lookup using the Bibdata Service
212
        items.each do |holding_id, mfhd_items|
275✔
213
          next if mfhd != holding_id
275✔
214
          requestable_items = build_requestable_from_mfhd_items(requestable_items:, holding_id:, mfhd_items:, barcodesort:)
275✔
215
        end
216
        requestable_items.compact
275✔
217
      end
218

219
      # @return [Array<Requests::Requestable>] array containing Requests::Requestables or empty array
220
      def build_requestable_from_data
3✔
221
        return if doc[:holdings_1display].blank?
2✔
222
        return [] if holdings[@mfhd].blank?
2✔
223

224
        [build_requestable_from_holding(@mfhd, holdings[@mfhd].with_indifferent_access)]
2✔
225
      end
226

227
      def build_requestable_from_mfhd_items(requestable_items:, holding_id:, mfhd_items:, barcodesort:)
3✔
228
        if !mfhd_items.empty?
275✔
229
          mfhd_items.each do |item|
235✔
230
            requestable_items << build_requestable_mfhd_item(holding_id, item, barcodesort)
2,251✔
231
          end
232
        else
233
          requestable_items << build_requestable_from_holding(holding_id, holdings[holding_id])
40✔
234
        end
235
        requestable_items.compact
275✔
236
      end
237

238
      def holding_data(item, holding_id, item_location_code)
3✔
239
        if item["in_temp_library"] && item["temp_location_code"] != "RES_SHARE$IN_RS_REQ"
2,244✔
240
          holdings[item_location_code]
8✔
241
        else
242
          holdings[holding_id]
2,236✔
243
        end
244
      end
245

246
      # Item we get from the 'load_items' live call to bibdata
247
      def build_requestable_mfhd_item(holding_id, item, barcodesort)
3✔
248
        return if item['on_reserve'] == 'Y'
2,251✔
249
        item['status_label'] = barcodesort[item['barcode']][:status_label] unless barcodesort.empty?
2,244✔
250
        item_current_location = item_current_location(item)
2,244✔
251
        params = build_requestable_params(
2,244✔
252
          item: item.with_indifferent_access,
253
          holding: Holding.new(mfhd_id: holding_id.to_sym.to_s, holding_data: holding_data(item, holding_id, item_location_code)),
254
          location: item_current_location
255
        )
256
        Requests::Requestable.new(**params)
2,244✔
257
      end
258

259
      def get_current_location(item_location_code:)
3✔
260
        if item_location_code != location_code
2,244✔
261
          @temp_locations ||= {}
10✔
262
          @temp_locations[item_location_code] = get_location_data(item_location_code) if @temp_locations[item_location_code].blank?
10✔
263
        else
264
          location
2,234✔
265
        end
266
      end
267

268
      # This method will always return a Requestable object where .item is a NullItem, because we don't pass an item in
269
      def build_requestable_from_holding(holding_id, holding)
3✔
270
        return if holding.blank?
42✔
271
        params = build_requestable_params(holding: Holding.new(mfhd_id: holding_id.to_sym.to_s, holding_data: holding), location:)
36✔
272
        Requests::Requestable.new(**params)
36✔
273
      end
274

275
      def load_bibdata_location
3✔
276
        return if location_code.blank?
309✔
277
        location = get_location_data(location_code)
297✔
278
        location_object = Location.new location
297✔
279
        location[:delivery_locations] = location_object.sort_pick_ups if location_object.delivery_locations.present?
297✔
280
        location
297✔
281
      end
282

283
      def build_requestable_params(params)
3✔
284
        {
285
          bib: doc,
2,342✔
286
          holding: params[:holding],
287
          item: params[:item],
288
          location: build_requestable_location(params),
289
          patron:
290
        }
291
      end
292

293
      def build_requestable_location(params)
3✔
294
        location = params[:location]
2,342✔
295
        location_object = Location.new location
2,342✔
296
        location["delivery_locations"] = location_object.build_delivery_locations if location_object.delivery_locations.present?
2,342✔
297
        location
2,342✔
298
      end
299

300
      ## Loads item availability through the Request Bibdata service using the items_by_mfhd method
301
      # items_by_mfhd makes the availabiliy call:
302
      # bibdata_conn.get "/bibliographic/#{system_id}/holdings/#{mfhd_id}/availability.json"
303
      # rename to: load_items_by_holding_id
304
      def load_items_by_mfhd
3✔
305
        mfhd_items = {}
307✔
306
        mfhd_items[@mfhd] = items_by_mfhd(@system_id, @mfhd)
307✔
307
        mfhd_items
307✔
308
      end
309

310
      def items_to_symbols(items = [])
3✔
UNCOV
311
        items_with_symbols = []
×
UNCOV
312
        items.each do |item|
×
UNCOV
313
          items_with_symbols << item.with_indifferent_access
×
314
        end
UNCOV
315
        items_with_symbols
×
316
      end
317

318
      def item_current_location(item)
3✔
319
        @item_location_code = if item['in_temp_library']
2,244✔
320
                                item['temp_location_code']
10✔
321
                              else
322
                                item['location']
2,234✔
323
                              end
324
        get_current_location(item_location_code:)
2,244✔
325
      end
326
      attr_reader :item_location_code
3✔
327
  end
328
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