From 151f116f3394f2f122918d1286cb46a0541eb66e Mon Sep 17 00:00:00 2001 From: CEdwardsBlasikiewicz Date: Mon, 17 Jun 2024 11:49:51 +1000 Subject: [PATCH] show item availability status --- app/controllers/catalog_controller.rb | 1 + app/models/solr_document.rb | 8 + app/services/catalogue_services_client.rb | 75 ++++ .../08aed703-3648-54d0-80ef-fddb3c635731.json | 370 ++++++++++++++++++ .../catalogue_services_client_spec.rb | 82 ++++ 5 files changed, 536 insertions(+) create mode 100644 app/services/catalogue_services_client.rb create mode 100644 spec/files/catalogue_services/08aed703-3648-54d0-80ef-fddb3c635731.json create mode 100644 spec/services/catalogue_services_client_spec.rb diff --git a/app/controllers/catalog_controller.rb b/app/controllers/catalog_controller.rb index 1738ed53..3b5a0633 100644 --- a/app/controllers/catalog_controller.rb +++ b/app/controllers/catalog_controller.rb @@ -302,6 +302,7 @@ class CatalogController < ApplicationController config.add_summary_field "extent", field: "extent_ssm" config.add_summary_field "language", field: "language_ssim" config.add_summary_field "prefercite", field: "prefercite_html_tesm", helper_method: :render_html_tags + config.add_summary_field "availability", field: "availability_status", accessor: :availability_status config.add_summary_field "cult_sens_adv_notice", label: I18n.t("ead_notes.cultural_sens_adv_notice"), helper_method: :render_html_tags, diff --git a/app/models/solr_document.rb b/app/models/solr_document.rb index ec256348..2c5760b4 100644 --- a/app/models/solr_document.rb +++ b/app/models/solr_document.rb @@ -95,4 +95,12 @@ def wrap_in_paragraph(value) value end end + + def availability_status + holdings, item = CatalogueServicesClient.new.get_item_ids(instance_id: self["folio_instance_id_ssi"]) + p "solrdoc" + pp [holdings, item] + + CatalogueServicesClient.new.get_requestable(instance_id: self["folio_instance_id_ssi"], holdings_id: holdings, item_id: item) + end end diff --git a/app/services/catalogue_services_client.rb b/app/services/catalogue_services_client.rb new file mode 100644 index 00000000..3bb07889 --- /dev/null +++ b/app/services/catalogue_services_client.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +class ServiceTokenError < StandardError; end + +class HoldingsRequestError < StandardError; end + +class ItemRequestError < StandardError; end + +class RequestDetailsError < StandardError; end + +class UserDetailsError < StandardError; end + +class CatalogueServicesClient + MAX_TOKEN_RETRIES = 3 + + def get_holdings(instance_id:) + conn = setup_connection + + res = conn.get("/catalogue-services/folio/instance/#{instance_id}") + if res.status == 200 + if res.body.present? + res.body["holdingsRecords"] + end + else + Rails.logger.error "Failed to retrieve holdings for #{instance_id}" + raise HoldingsRequestError.new("Failed to retrieve holdings for #{instance_id}") + end + rescue => e + Rails.logger.error "get_holdings - Failed to connect catalogue-service: #{e.message}" + raise HoldingsRequestError.new("Failed to retrieve holdings for #{instance_id}") + end + + def get_holding(instance_id:, holdings_id:, item_id:) + all_holdings = get_holdings(instance_id: instance_id) + + # find holdings record + holding = all_holdings.find { |h| h["id"] == holdings_id } + + # find item record + item = holding["itemRecords"].find { |i| i["id"] == item_id } + + [holding, item] + end + + def get_requestable(instance_id:, holdings_id:, item_id:) + all_holdings = get_holdings(instance_id: instance_id) + + # find holdings record + holding = all_holdings.find { |h| h["id"] == holdings_id } + + # find item record + item = holding["itemRecords"].find { |i| i["id"] == item_id } + + item["requestable"] ? item["displayStatus"] : "Not for loan" + end + + def get_item_ids(instance_id:) + all_holdings = get_holdings(instance_id: instance_id) + + item_id = all_holdings.first["itemRecords"].first["holdingsRecordId"] if all_holdings.first["itemRecords"].any? + + holding_id = all_holdings.first["itemRecords"].first["id"] if all_holdings.first["itemRecords"].any? + p "catservices" + pp [item_id, holding_id] + [item_id, holding_id] + end + + private + + def setup_connection + Faraday.new(url: ENV["CATALOGUE_SERVICES_API_BASE_URL"]) do |f| + f.response :json + end + end +end diff --git a/spec/files/catalogue_services/08aed703-3648-54d0-80ef-fddb3c635731.json b/spec/files/catalogue_services/08aed703-3648-54d0-80ef-fddb3c635731.json new file mode 100644 index 00000000..5162bc2a --- /dev/null +++ b/spec/files/catalogue_services/08aed703-3648-54d0-80ef-fddb3c635731.json @@ -0,0 +1,370 @@ +{ + "instanceId": "08aed703-3648-54d0-80ef-fddb3c635731", + "holdingsRecords": [ + { + "id": "d6c97d9e-dfe6-5faa-9f0b-020b2bddbf8c", + "instanceId": "08aed703-3648-54d0-80ef-fddb3c635731", + "permanentLocationId": "e041308f-c160-48b6-b6e7-cd5d0d582122", + "effectiveLocationId": "e041308f-c160-48b6-b6e7-cd5d0d582122", + "callNumber": "NL 919.4 NAT", + "holdingsStatements": [ + { + "statement": "", + "note": "v. 124, no. 3 (Sept. 1963)", + "staffNote": "" + } + ], + "holdingsStatementsForIndexes": [], + "holdingsStatementsForSupplements": [], + "discoverySuppress": false, + "itemRecords": [ + { + "id": "7460acfb-72b9-5dba-9089-603921fb47c7", + "holdingsRecordId": "d6c97d9e-dfe6-5faa-9f0b-020b2bddbf8c", + "barcode": "78000000165101", + "effectiveLocationId": "e041308f-c160-48b6-b6e7-cd5d0d582122", + "effectiveLocationDisplayName": "Main Reading Room", + "effectiveCallNumberComponents": { + "callNumber": "NL 919.4 NAT" + }, + "status": { + "name": "Available", + "date": "2023-06-28T04:08:47.034+00:00" + }, + "pickupLocation": { + "id": "325aea8b-f5f2-4160-88ca-63d803856a70", + "name": "Main Reading Room", + "code": "MRR-SP", + "discoveryDisplayName": "Main Reading Room", + "pickupLocation": true, + "holdShelfExpiryPeriod": { + "duration": 6, + "intervalId": "Days" + } + }, + "materialTypeId": "237cc266-f677-4b8e-aaae-846ed7e66361", + "permanentLoanTypeId": "ec500417-ea68-484f-858d-e8f6166e6237", + "yearCaption": [], + "enumeration": "NL pbk", + "itemCategory": "monograph", + "discoverySuppress": false, + "requestable": true, + "displayStatus": "Available" + } + ], + "notes": [], + "checkedOutItems": [] + }, + { + "id": "44e5936d-0bd9-5df5-a86a-5091d04bd84d", + "instanceId": "08aed703-3648-54d0-80ef-fddb3c635731", + "permanentLocationId": "14b466b6-86b3-499b-9ddb-262fa0ac56ce", + "effectiveLocationId": "14b466b6-86b3-499b-9ddb-262fa0ac56ce", + "callNumber": "N 919.4 NAT", + "holdingsStatements": [ + { + "statement": "", + "note": "N pbk", + "staffNote": "" + } + ], + "holdingsStatementsForIndexes": [], + "holdingsStatementsForSupplements": [], + "discoverySuppress": false, + "itemRecords": [ + { + "id": "52209e0d-00bd-5f19-91e8-55e1314ef637", + "holdingsRecordId": "44e5936d-0bd9-5df5-a86a-5091d04bd84d", + "barcode": "78000000175193", + "effectiveLocationId": "14b466b6-86b3-499b-9ddb-262fa0ac56ce", + "effectiveLocationDisplayName": "Main Reading Room", + "effectiveCallNumberComponents": { + "callNumber": "N 919.4 NAT" + }, + "status": { + "name": "Available", + "date": "2023-06-28T04:01:37.430+00:00" + }, + "pickupLocation": { + "id": "325aea8b-f5f2-4160-88ca-63d803856a70", + "name": "Main Reading Room", + "code": "MRR-SP", + "discoveryDisplayName": "Main Reading Room", + "pickupLocation": true, + "holdShelfExpiryPeriod": { + "duration": 6, + "intervalId": "Days" + } + }, + "materialTypeId": "237cc266-f677-4b8e-aaae-846ed7e66361", + "permanentLoanTypeId": "ec500417-ea68-484f-858d-e8f6166e6237", + "yearCaption": [], + "enumeration": "N pbk", + "itemCategory": "monograph", + "discoverySuppress": false, + "requestable": true, + "displayStatus": "Available" + } + ], + "notes": [], + "checkedOutItems": [] + }, + { + "id": "fc59f835-c340-5ea4-978d-4bfe4193cee0", + "instanceId": "08aed703-3648-54d0-80ef-fddb3c635731", + "permanentLocationId": "4ac9fcf1-8288-41b5-ac14-e15648f97158", + "effectiveLocationId": "4ac9fcf1-8288-41b5-ac14-e15648f97158", + "callNumber": "HSW 2071", + "holdingsStatements": [ + { + "statement": "", + "note": "Vol. 118, no. 2 (Aug. 1960); v. 118, no. 6 (Dec. 1960); v. 121, no. 1 (Jan. 1962); v. 126, no. 4 (Oct. 1964)-v. 126, no. 5 (Nov. 1964); v. 131, no. 2 (Feb. 1967); v. 132, no. 3 (Sept. 1967); v. 134, no. 6 (Dec. 1968)-v. 135, no. 1 (Jan. 1969); v. 135, no. 3 (March 1969)-v. 135, no. 4 (April 1969); v. 136, no. 3 (Sept. 1969); v. 137, no. 3 (March 1970); v. 138, no. 5 (Nov. 1970); v. 140, no. 1 (July 1971); v. 149, no. 6 (June 1976); v. 152, no. 6 (Dec. 1977)", + "staffNote": "" + } + ], + "holdingsStatementsForIndexes": [], + "holdingsStatementsForSupplements": [], + "discoverySuppress": false, + "itemRecords": [ + { + "id": "95d87c3b-ef17-5440-9dbb-befcc2b7670b", + "holdingsRecordId": "fc59f835-c340-5ea4-978d-4bfe4193cee0", + "barcode": "31508019674725", + "effectiveLocationId": "4ac9fcf1-8288-41b5-ac14-e15648f97158", + "effectiveLocationDisplayName": "Special Collections Reading Room", + "effectiveCallNumberComponents": { + "callNumber": "HSW 2071" + }, + "status": { + "name": "Available", + "date": "2023-06-28T03:59:00.959+00:00" + }, + "pickupLocation": { + "id": "d1624450-96b9-48ac-9457-47d7d4924c66", + "name": "Special Collections Reading Room", + "code": "SCRR-SP", + "discoveryDisplayName": "Special Collections Reading Room", + "pickupLocation": true, + "holdShelfExpiryPeriod": { + "duration": 6, + "intervalId": "Days" + } + }, + "materialTypeId": "237cc266-f677-4b8e-aaae-846ed7e66361", + "permanentLoanTypeId": "ec500417-ea68-484f-858d-e8f6166e6237", + "yearCaption": [], + "enumeration": "FOR REQUESTS, USE THE REQUEST OPTION BELOW", + "itemCategory": "journal", + "discoverySuppress": false, + "requestable": true, + "displayStatus": "Available" + } + ], + "notes": [ + { + "note": "(Aug.1960 - Dec.1977) impf", + "staffOnly": false, + "holdingsNoteTypeId": "b160f13a-ddba-4053-b9c4-60ec5ea45d56", + "holdingsNoteType": "Note" + } + ], + "checkedOutItems": [] + }, + { + "id": "37fbc2dd-3b37-58b8-b447-b538ba7265b9", + "instanceId": "08aed703-3648-54d0-80ef-fddb3c635731", + "permanentLocationId": "7b4822a2-9aa7-442d-8ed5-8da3cc8c01a2", + "effectiveLocationId": "7b4822a2-9aa7-442d-8ed5-8da3cc8c01a2", + "callNumber": "NKA 1132", + "holdingsStatements": [ + { + "statement": "", + "note": "Vol. 148, no. 5 (Nov. 1975)-vol. 148, no. 6 (Dec. 1975)", + "staffNote": "" + } + ], + "holdingsStatementsForIndexes": [], + "holdingsStatementsForSupplements": [], + "discoverySuppress": false, + "itemRecords": [ + { + "id": "60ae1cf9-5b4c-5fac-9a38-2cb195cdb7b2", + "holdingsRecordId": "37fbc2dd-3b37-58b8-b447-b538ba7265b9", + "barcode": "31508021167700", + "effectiveLocationId": "7b4822a2-9aa7-442d-8ed5-8da3cc8c01a2", + "effectiveLocationDisplayName": "Special Collections Reading Room", + "effectiveCallNumberComponents": { + "callNumber": "NKA 1132" + }, + "status": { + "name": "Available", + "date": "2023-06-28T03:57:31.846+00:00" + }, + "pickupLocation": { + "id": "d1624450-96b9-48ac-9457-47d7d4924c66", + "name": "Special Collections Reading Room", + "code": "SCRR-SP", + "discoveryDisplayName": "Special Collections Reading Room", + "pickupLocation": true, + "holdShelfExpiryPeriod": { + "duration": 6, + "intervalId": "Days" + } + }, + "materialTypeId": "237cc266-f677-4b8e-aaae-846ed7e66361", + "permanentLoanTypeId": "ec500417-ea68-484f-858d-e8f6166e6237", + "yearCaption": [], + "itemCategory": "monograph", + "discoverySuppress": false, + "requestable": true, + "displayStatus": "Available" + } + ], + "notes": [ + { + "note": "(Nov.1975 - Dec.1975)", + "staffOnly": false, + "holdingsNoteTypeId": "b160f13a-ddba-4053-b9c4-60ec5ea45d56", + "holdingsNoteType": "Note" + } + ], + "checkedOutItems": [] + }, + { + "id": "fe525746-5142-5b54-8c89-c6ed7a9c6196", + "instanceId": "08aed703-3648-54d0-80ef-fddb3c635731", + "permanentLocationId": "11c74e44-110d-4e53-8418-cf4bad1e314a", + "effectiveLocationId": "11c74e44-110d-4e53-8418-cf4bad1e314a", + "callNumber": "S 910.5 NAT", + "holdingsStatements": [ + { + "statement": "v. 116, no. 6 - v. 218, no. 1 (1959:Dec. - 2010:July)", + "note": "", + "staffNote": "" + }, + { + "statement": "v. 218, no. 4 - v. 222, no. 2 (2010:Oct. - 2012:Aug.)", + "note": "", + "staffNote": "" + }, + { + "statement": "v. 222, no. 4 - v. 244, no. 5 (2012:Oct. - 2023:Nov.)", + "note": "", + "staffNote": "" + } + ], + "holdingsStatementsForIndexes": [ + { + "statement": "", + "note": "Cumulative index", + "staffNote": "" + }, + { + "statement": "", + "note": "1888-1988", + "staffNote": "" + }, + { + "statement": "", + "note": "1989-1998", + "staffNote": "" + }, + { + "statement": "2001", + "note": "", + "staffNote": "" + }, + { + "statement": "2003", + "note": "", + "staffNote": "" + }, + { + "statement": "2008", + "note": "", + "staffNote": "" + } + ], + "holdingsStatementsForSupplements": [ + { + "statement": "", + "note": "Maps of the United States and the world and cartography at the National Geographic Society, 1888-1988", + "staffNote": "" + }, + { + "statement": "", + "note": "Energy (Feb 1981)", + "staffNote": "" + }, + { + "statement": "", + "note": "Traveler's map of Germany (Sept 1991)", + "staffNote": "" + }, + { + "statement": "", + "note": "Native American heritage: a visitors guide (Oct 1991)", + "staffNote": "" + }, + { + "statement": "", + "note": "Water (v.184 ,no. 5A, 1993)", + "staffNote": "" + }, + { + "statement": "", + "note": "Millennium Supplement: Population (Oct 1998)", + "staffNote": "" + }, + { + "statement": "", + "note": "Supplement: Millennium in maps: cultures (Aug 1999)", + "staffNote": "" + }, + { + "statement": "", + "note": "Special millennium issue (Jan 2000)", + "staffNote": "" + } + ], + "discoverySuppress": false, + "itemRecords": [ + { + "id": "0f17532a-2fcf-5c72-a0c9-751fc459481f", + "holdingsRecordId": "fe525746-5142-5b54-8c89-c6ed7a9c6196", + "barcode": "31508002260425", + "effectiveLocationId": "11c74e44-110d-4e53-8418-cf4bad1e314a", + "effectiveLocationDisplayName": "Main Reading Room - Most pre 2005 held offsite", + "effectiveCallNumberComponents": { + "callNumber": "S 910.5 NAT" + }, + "status": { + "name": "Available", + "date": "2023-06-28T03:04:28.167+00:00" + }, + "pickupLocation": { + "id": "325aea8b-f5f2-4160-88ca-63d803856a70", + "name": "Main Reading Room", + "code": "MRR-SP", + "discoveryDisplayName": "Main Reading Room", + "pickupLocation": true, + "holdShelfExpiryPeriod": { + "duration": 6, + "intervalId": "Days" + } + }, + "materialTypeId": "237cc266-f677-4b8e-aaae-846ed7e66361", + "permanentLoanTypeId": "ec500417-ea68-484f-858d-e8f6166e6237", + "yearCaption": [], + "enumeration": "FOR REQUESTS, USE THE REQUEST OPTION BELOW", + "itemCategory": "journal", + "discoverySuppress": false, + "requestable": true, + "displayStatus": "Available" + } + ], + "notes": [], + "checkedOutItems": [] + } + ] +} \ No newline at end of file diff --git a/spec/services/catalogue_services_client_spec.rb b/spec/services/catalogue_services_client_spec.rb new file mode 100644 index 00000000..e213d3ed --- /dev/null +++ b/spec/services/catalogue_services_client_spec.rb @@ -0,0 +1,82 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe CatalogueServicesClient do + subject(:service) { described_class.new } + + # WebMock.stub_request(:get, "http://catservices.test/catalogue-services/folio/instance/6bf69425-293d-5e3f-a050-16124aca9a4e"). + # with( + # headers: { + # 'Accept'=>'*/*', + # 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', + # }). + # to_return(status: 200, body: "", headers: {}) + + describe "#get_holdings" do + context "when unable to request holdings" do + it "raises a ItemRequestError" do + WebMock.stub_request(:get, "http://catservices.test/catalogue-services/folio/instance/08aed703-3648-54d0-80ef-fddb3c635731") + .with( + headers: { + "Accept" => "*/*", + "Accept-Encoding" => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3" + } + ) + .to_return(status: 401, body: "", headers: {}) + + expect { service.get_holdings(instance_id: "08aed703-3648-54d0-80ef-fddb3c635731") }.to raise_error(HoldingsRequestError) + end + end + + context "when requesting holdings records" do + it "returns holdings records" do + # ________________from file + cat_response = IO.read("spec/files/catalogue_services/08aed703-3648-54d0-80ef-fddb3c635731.json") + WebMock.stub_request(:get, "http://catservices.test/catalogue-services/folio/instance/08aed703-3648-54d0-80ef-fddb3c635731") + .with( + headers: { + "Accept" => "*/*", + "Accept-Encoding" => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3" + } + ) + .to_return(status: 200, body: cat_response, headers: {}) + + # ________________empty stub + # WebMock.stub_request(:get, "http://catservices.test/catalogue-services/folio/instance/08aed703-3648-54d0-80ef-fddb3c635731") + # .with( + # headers: { + # "Accept" => "*/*", + # "Accept-Encoding" => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3" + # } + # ) + # .to_return(status: 200, body: "", headers: {}) + + pp service.get_holdings(instance_id: "08aed703-3648-54d0-80ef-fddb3c635731") + expect(service.get_holdings(instance_id: "08aed703-3648-54d0-80ef-fddb3c635731").size).to eq 5 + end + end + end + + + # describe "#get_holdings" do + # it "returns holdings records" do + # pp service.get_holdings(instance_id: "6bf69425-293d-5e3f-a050-16124aca9a4e") + # expect(service.get_holdings(instance_id: "6bf69425-293d-5e3f-a050-16124aca9a4e")).to eq 1 + # end + # end + + # describe "#get_item_ids" do + # it "returns item id and holding id" do + # expect(service.get_item_ids(instance_id: "6bf69425-293d-5e3f-a050-16124aca9a4e")).to eq %w[565c607a-4a21-5a9c-bc22-370947bb9a7c bed76196-e6ed-50d8-b658-ef64ce8ad90e] + # end + # end + # + # describe "#get_requestable" do + # it "returns item's requestable status" do + # expect(service.get_requestable(instance_id: "6bf69425-293d-5e3f-a050-16124aca9a4e", + # holdings_id: "565c607a-4a21-5a9c-bc22-370947bb9a7c", + # item_id: "bed76196-e6ed-50d8-b658-ef64ce8ad90e")).to eq false + # end + # end +end