diff --git a/bookops_worldcat/metadata_api.py b/bookops_worldcat/metadata_api.py index 499ebcd..19df8bf 100644 --- a/bookops_worldcat/metadata_api.py +++ b/bookops_worldcat/metadata_api.py @@ -1099,6 +1099,7 @@ def holdings_set( def holdings_unset( self, oclcNumber: Union[int, str], + cascadeDelete: bool = True, hooks: Optional[Dict[str, Callable]] = None, ) -> Response: """ @@ -1110,6 +1111,11 @@ def holdings_unset( oclcNumber: OCLC bibliographic record number. Can be an integer or string with or without OCLC Number prefix. + cascadeDelete: + Whether or not to remove any LBDs and/or LHRs associated with + the bib record on which holdings are being removed. If `False`, + associated local records will remain in WorldCat. If `True`, + local records will be removed from WorldCat. hooks: Requests library hook system that can be used for signal event handling. For more information see the [Requests docs](https://requests. @@ -1123,8 +1129,10 @@ def holdings_unset( url = self._url_manage_ih_unset(oclcNumber) header = {"Accept": "application/json"} + payload = {"cascadeDelete": cascadeDelete} + # prep request - req = Request("POST", url, headers=header, hooks=hooks) + req = Request("POST", url, params=payload, headers=header, hooks=hooks) prepared_request = self.prepare_request(req) # send request @@ -1179,6 +1187,7 @@ def holdings_unset_with_bib( self, record: str, recordFormat: str, + cascadeDelete: bool = True, hooks: Optional[Dict[str, Callable]] = None, ) -> Response: """ @@ -1195,6 +1204,11 @@ def holdings_unset_with_bib( Format of MARC record. **OPTIONS:** `'application/marcxml+xml'` or `'application/marc'` + cascadeDelete: + Whether or not to remove any LBDs and/or LHRs associated with + the bib record on which holdings are being removed. If `False`, + associated local records will remain in WorldCat. If `True`, + local records will be removed from WorldCat. hooks: Requests library hook system that can be used for signal event handling. For more information see the [Requests docs](https://requests. @@ -1203,14 +1217,24 @@ def holdings_unset_with_bib( Returns: `requests.Response` instance """ + url = self._url_manage_ih_unset_with_bib() header = { "Accept": "application/json", "content-type": recordFormat, } + payload = {"cascadeDelete": cascadeDelete} + # prep request - req = Request("POST", url, data=record, headers=header, hooks=hooks) + req = Request( + "POST", + url, + data=record, + params=payload, + headers=header, + hooks=hooks, + ) prepared_request = self.prepare_request(req) # send request diff --git a/docs/local.md b/docs/local.md index 7e92769..88c6739 100644 --- a/docs/local.md +++ b/docs/local.md @@ -1,6 +1,7 @@ # Search and Manage Local Data New functionality available in Version 1.0 of Bookops-Worldcat allows users to search and manage local bibliographic and holdings data via the Metadata API. +Users can also manage local bibliographic and holdings data when managing institution holdings. When unsetting holdings on a record in OCLC, users can remove associated LBDs and/or LHRs. See[Manage Institution Holdings > Set and Unset Holdings](manage_holdings.md#set-and-unset-holdings) for more information. ### Manage Local Bib Records Users can manage local bib records in WorldCat in the same way that they manage WorldCat records (see [Managing Bibliographic Records](manage_bibs.md) for more information). Records can be retrieved in MARCXML or MARC21 formats. The default format for records is MARCXML. diff --git a/docs/manage_holdings.md b/docs/manage_holdings.md index a0d48f5..84b1cec 100644 --- a/docs/manage_holdings.md +++ b/docs/manage_holdings.md @@ -60,6 +60,8 @@ Version 2.0 of the Metadata API provides new functionality to set and unset hold Bookops-Worldcat supports this functionality with the `holdings_set_with_bib` and `holdings_unset_with_bib` methods which can be passed a MARC record in the body of the request in the same way that one would pass a record to a method that uses any of the `/manage/bibs/` endpoints. +Beginning in September 2024 users are able to remove associated Local Bibliographic Data and/or Local Holdings Records when unsetting holdings on a record in OCLC. This functionality is supported by both the `/worldcat/manage/institution/holdings/unset` and `/worldcat/manage/institution/holdings/{oclcNumber}/unset` endpoints using the `cascadeDelete` arg. If `cascadeDelete` is `True`, local records will be removed from WorldCat when unsetting a holding. If `False`, the associated local records will remain in WorldCat. The default value within `bookops-worldcat` and the Metadata API is `True` + === "holdings_set" ```python title="holdings_set Request" diff --git a/tests/test_metadata_api.py b/tests/test_metadata_api.py index 95b9e65..be30b96 100644 --- a/tests/test_metadata_api.py +++ b/tests/test_metadata_api.py @@ -483,6 +483,15 @@ def test_holdings_set_None_oclcNumber_passed(self, stub_session): def test_holdings_unset(self, stub_session, mock_session_response): assert stub_session.holdings_unset(850940548).status_code == 200 + @pytest.mark.http_code(200) + def test_holdings_unset_cascadeDelete_false( + self, stub_session, mock_session_response + ): + assert ( + stub_session.holdings_unset(850940548, cascadeDelete=False).status_code + == 200 + ) + def test_holdings_unset_no_oclcNumber_passed(self, stub_session): with pytest.raises(TypeError): stub_session.holdings_unset() @@ -981,7 +990,40 @@ def test_holdings_set_unset(self, live_keys): assert response.status_code == 200 assert ( response.request.url - == "https://metadata.api.oclc.org/worldcat/manage/institution/holdings/850940548/unset" + == "https://metadata.api.oclc.org/worldcat/manage/institution/holdings/850940548/unset?cascadeDelete=True" + ) + assert response.json()["action"] == "Unset Holdings" + + @pytest.mark.holdings + def test_holdings_set_unset_cascadeDelete_False(self, live_keys, stub_marc_xml): + token = WorldcatAccessToken( + key=os.getenv("WCKey"), + secret=os.getenv("WCSecret"), + scopes=os.getenv("WCScopes"), + ) + + with MetadataSession(authorization=token) as session: + response = session.holdings_get_current("850940548") + holdings = response.json()["holdings"] + + # make sure no holdings are set initially + if len(holdings) > 0: + response = session.holdings_unset(850940548) + + response = session.holdings_set(850940548) + assert ( + response.url + == "https://metadata.api.oclc.org/worldcat/manage/institution/holdings/850940548/set" + ) + assert response.status_code == 200 + assert response.json()["action"] == "Set Holdings" + + # test deleting holdings + response = session.holdings_unset(850940548, cascadeDelete=False) + assert response.status_code == 200 + assert ( + response.request.url + == "https://metadata.api.oclc.org/worldcat/manage/institution/holdings/850940548/unset?cascadeDelete=False" ) assert response.json()["action"] == "Unset Holdings" @@ -1019,7 +1061,50 @@ def test_holdings_set_unset_marcxml(self, live_keys, stub_marc_xml): assert response.status_code == 200 assert ( response.request.url - == "https://metadata.api.oclc.org/worldcat/manage/institution/holdings/unset" + == "https://metadata.api.oclc.org/worldcat/manage/institution/holdings/unset?cascadeDelete=True" + ) + assert response.json()["action"] == "Unset Holdings" + + @pytest.mark.holdings + def test_holdings_set_unset_marcxml_cascadeDelete_False( + self, live_keys, stub_marc_xml + ): + token = WorldcatAccessToken( + key=os.getenv("WCKey"), + secret=os.getenv("WCSecret"), + scopes=os.getenv("WCScopes"), + ) + + with MetadataSession(authorization=token) as session: + response = session.holdings_get_current("850940548") + holdings = response.json()["holdings"] + + # make sure no holdings are set initially + if len(holdings) > 0: + response = session.holdings_unset_with_bib( + stub_marc_xml, recordFormat="application/marcxml+xml" + ) + + response = session.holdings_set_with_bib( + stub_marc_xml, recordFormat="application/marcxml+xml" + ) + assert ( + response.url + == "https://metadata.api.oclc.org/worldcat/manage/institution/holdings/set" + ) + assert response.status_code == 200 + assert response.json()["action"] == "Set Holdings" + + # test deleting holdings + response = session.holdings_unset_with_bib( + stub_marc_xml, + recordFormat="application/marcxml+xml", + cascadeDelete=False, + ) + assert response.status_code == 200 + assert ( + response.request.url + == "https://metadata.api.oclc.org/worldcat/manage/institution/holdings/unset?cascadeDelete=False" ) assert response.json()["action"] == "Unset Holdings"