From 98cc0dcfed5f0d547114b7f798d5067a4d5c55f9 Mon Sep 17 00:00:00 2001 From: Pedro Amorim Date: Wed, 30 Jul 2025 11:28:16 +0000 Subject: [PATCH] Bug 40550: Add cancellation_bulk API endpoint --- Koha/REST/V1/Holds.pm | 44 +++++++++++++++++++++++++ api/v1/swagger/paths/holds.yaml | 58 +++++++++++++++++++++++++++++++++ api/v1/swagger/swagger.yaml | 2 ++ 3 files changed, 104 insertions(+) diff --git a/Koha/REST/V1/Holds.pm b/Koha/REST/V1/Holds.pm index 53abf9c2cdf..bda70f5980e 100644 --- a/Koha/REST/V1/Holds.pm +++ b/Koha/REST/V1/Holds.pm @@ -340,6 +340,50 @@ sub delete { }; } +=head3 delete_bulk + +Method that handles deleting multiple Koha::Hold objects + +=cut + +sub delete_bulk { + my $c = shift->openapi->valid_input or return; + + my $body = $c->req->json; + my $hold_ids = ($body) ? $body->{hold_ids} : undef; + my $cancellation_reason = ($body) ? $body->{cancellation_reason} : undef; + + return $c->render_resource_not_found("Hold") + unless $hold_ids; + + foreach my $hold_id (@$hold_ids) { + my $hold = Koha::Holds->find($hold_id); + return $c->render_resource_not_found( "Hold", "id", $hold_id ) + unless $hold; + } + + return try { + Koha::Database->new->schema->txn_do( + sub { + foreach my $hold_id (@$hold_ids) { + my $hold = Koha::Holds->find($hold_id); + $hold->cancel( { cancellation_reason => $cancellation_reason } ); + } + $c->res->headers->location( $c->req->url->to_string ); + return $c->render( + status => 204, + openapi => { + hold_ids => $hold_ids, + cancellation_reason => $cancellation_reason, + } + ); + } + ); + } catch { + $c->unhandled_exception($_); + }; +} + =head3 suspend Method that handles suspending a hold diff --git a/api/v1/swagger/paths/holds.yaml b/api/v1/swagger/paths/holds.yaml index 73e2b7982c8..435246c953d 100644 --- a/api/v1/swagger/paths/holds.yaml +++ b/api/v1/swagger/paths/holds.yaml @@ -340,6 +340,64 @@ x-koha-authorization: permissions: reserveforothers: place_holds +"/holds/cancellation_bulk": + delete: + x-mojo-to: Holds#delete_bulk + operationId: deleteHolds + tags: + - holds + summary: Cancel holds + parameters: + - name: body + in: body + description: Hold ids + required: true + schema: + type: object + properties: + cancellation_reason: + description: Cancellation reason + type: string + hold_ids: + type: array + items: + type: integer + additionalProperties: false + produces: + - application/json + responses: + "204": + description: Holds deleted + "400": + description: Bad request + schema: + $ref: "../swagger.yaml#/definitions/error" + "401": + description: Authentication required + schema: + $ref: "../swagger.yaml#/definitions/error" + "403": + description: Hold not allowed + schema: + $ref: "../swagger.yaml#/definitions/error" + "404": + description: Hold not found + schema: + $ref: "../swagger.yaml#/definitions/error" + "500": + description: | + Internal server error. Possible `error_code` attribute values: + + * `internal_server_error` + schema: + $ref: "../swagger.yaml#/definitions/error" + "503": + description: Under maintenance + schema: + $ref: "../swagger.yaml#/definitions/error" + x-koha-authorization: + permissions: + reserveforothers: place_holds "/holds/{hold_id}": patch: x-mojo-to: Holds#edit diff --git a/api/v1/swagger/swagger.yaml b/api/v1/swagger/swagger.yaml index f99cf2eecd9..152e66ccf88 100644 --- a/api/v1/swagger/swagger.yaml +++ b/api/v1/swagger/swagger.yaml @@ -405,6 +405,8 @@ paths: $ref: ./paths/holds.yaml#/~1holds "/holds/suspension_bulk": $ref: "./paths/holds.yaml#/~1holds~1suspension_bulk" + "/holds/cancellation_bulk": + $ref: "./paths/holds.yaml#/~1holds~1cancellation_bulk" "/holds/{hold_id}": $ref: "./paths/holds.yaml#/~1holds~1{hold_id}" "/holds/{hold_id}/pickup_location": -- 2.39.5