diff --git a/admin/columns_settings.yml b/admin/columns_settings.yml index 7b9e4e7ec8..0c3b904060 100644 --- a/admin/columns_settings.yml +++ b/admin/columns_settings.yml @@ -2046,7 +2046,52 @@ modules: columnname: suspend - columnname: print_slip - + holds_to_modify: + default_display_length: 20 + columns: + - + columnname: checkbox + cannot_be_toggled: 1 + cannot_be_modified: 1 + - + columnname: expiration_date + - + columnname: title + - + columnname: barcode + - + columnname: patron + - + columnname: status + - + columnname: pickup_library + - + columnname: suspended + - + columnname: suspended_until + - + columnname: notes + modified_holds: + default_display_length: 20 + columns: + - + columnname: expiration_date + - + columnname: title + - + columnname: barcode + - + columnname: patron + - + columnname: status + - + columnname: pickup_library + - + columnname: suspended + - + columnname: suspended_until + - + columnname: notes holdsratios: holds-ratios: default_display_length: 20 diff --git a/api/v1/swagger/definitions/hold.yaml b/api/v1/swagger/definitions/hold.yaml index af3cd55087..ce4d7327a9 100644 --- a/api/v1/swagger/definitions/hold.yaml +++ b/api/v1/swagger/definitions/hold.yaml @@ -135,6 +135,11 @@ properties: - object - "null" description: Pickup library + patron: + type: + - object + - "null" + description: Patron for hold _strings: type: - object diff --git a/api/v1/swagger/paths/holds.yaml b/api/v1/swagger/paths/holds.yaml index 57133753b1..388a446ab9 100644 --- a/api/v1/swagger/paths/holds.yaml +++ b/api/v1/swagger/paths/holds.yaml @@ -106,6 +106,8 @@ - biblio - deleted_biblio - pickup_library + - item + - patron collectionFormat: csv produces: - application/json diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/modals/batch_modify_hold_errors.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/modals/batch_modify_hold_errors.inc new file mode 100644 index 0000000000..ed9d152622 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/modals/batch_modify_hold_errors.inc @@ -0,0 +1,17 @@ + + diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/tools-menu.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/tools-menu.inc index 29a626aa1d..d8fc92d933 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/tools-menu.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/tools-menu.inc @@ -39,6 +39,9 @@ [% IF ( CAN_user_tools_batch_extend_due_dates ) %]
  • Batch extend due dates
  • [% END %] + [% IF ( CAN_user_tools_batch_modify_holds ) %] +
  • Batch modify holds
  • + [% END %] [% IF ( CAN_user_tools_moderate_tags ) %]
  • Tags
  • [% END %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/reports/guided_reports_start.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/reports/guided_reports_start.tt index 1e50498d74..57e7a1d74c 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/reports/guided_reports_start.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/reports/guided_reports_start.tt @@ -1071,6 +1071,16 @@ > +
    + [% INCLUDE 'csrf-token.inc' %] + + +
    + [% BLOCK batch_list %] [%- FOREACH result IN results %] [%- FOREACH cells IN result.cells %] @@ -1095,9 +1105,9 @@ - [% IF ( batch_biblionumbers || batch_itemnumbers || batch_cardnumbers || batch_borrowernumbers ) || ( unlimited_total > 10 && limit <= 1000 ) %] + [% IF ( batch_biblionumbers || batch_itemnumbers || batch_cardnumbers || batch_borrowernumbers || batch_reserve_ids ) || ( unlimited_total > 10 && limit <= 1000 ) %]
    - [% IF ( batch_biblionumbers || batch_itemnumbers || batch_cardnumbers || batch_borrowernumbers ) %] + [% IF ( batch_biblionumbers || batch_itemnumbers || batch_cardnumbers || batch_borrowernumbers || batch_reserve_ids ) %]
    - [% END # /IF ( batch_biblionumbers || batch_itemnumbers || batch_cardnumbers ) %] + [% END # /IF ( batch_biblionumbers || batch_itemnumbers || batch_cardnumbers || batch_reserve_ids ) %] [% IF ( unlimited_total > 10 && limit <= 1000 ) %]
    @@ -1238,7 +1262,7 @@
    [% END # /IF ( unlimited_total > 10 && limit <= 1000 ) %] - [% IF ( batch_biblionumbers || batch_itemnumbers || batch_cardnumbers ) %] + [% IF ( batch_biblionumbers || batch_itemnumbers || batch_cardnumbers || batch_reserve_ids ) %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/batch_modify_holds.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/batch_modify_holds.tt new file mode 100644 index 0000000000..b0fe375af1 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/batch_modify_holds.tt @@ -0,0 +1,716 @@ +[% USE raw %] +[% USE Asset %] +[% SET footerjs = 1 %] +[% USE Branches %] +[% USE Categories %] +[% USE KohaDates %] +[% USE ItemTypes %] +[% USE TablesSettings %] +[% USE To %] +[% PROCESS 'html_helpers.inc' %] + +[% INCLUDE 'doc-head-open.inc' %] +Batch modify holds › Tools › Koha +[% INCLUDE 'doc-head-close.inc' %] +[% Asset.css("css/humanmsg.css") | $raw %] + + + +[% WRAPPER 'header.inc' %] + [% INCLUDE 'cat-search.inc' %] + [% INCLUDE modals/batch_modify_hold_errors.inc %] +[% END %] +[% WRAPPER 'sub-header.inc' %] + [% WRAPPER breadcrumbs %] + [% WRAPPER breadcrumb_item %] + Tools + [% END %] + [% IF ( view == 'form' || view == 'report' ) %] + [% WRAPPER breadcrumb_item %] + Batch modify holds + [% END %] + [% ELSE %] + [% WRAPPER breadcrumb_item bc_active= 1 %] + Batch modify holds + [% END %] + [% END %] + [% END #/ WRAPPER breadcrumbs %] +[% END #/ WRAPPER sub-header.inc %] + +
    +
    +
    +
    +

    Batch modify holds

    + [% IF view == "cud-form" %] + + + [% ELSIF view == "report" %] + + + [% END %] + + +
    +
    + +
    + +
    + +
    + [% MACRO jsinclude BLOCK %] + [% Asset.js("js/tools-menu.js") | $raw %] + [% INCLUDE 'calendar.inc' %] + [% INCLUDE 'datatables.inc' %] + [% INCLUDE 'select2.inc' %] + [% INCLUDE 'js-patron-format.inc' %] + [% Asset.js("lib/jquery/plugins/humanmsg.js") | $raw %] + + [% END %] + + [% INCLUDE 'intranet-bottom.inc' %] +
    diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt index 3aa18b3963..f7839ed893 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt @@ -29,7 +29,7 @@

    Tools

    - [% IF ( CAN_user_tools_manage_patron_lists || CAN_user_clubs || CAN_user_tools_moderate_comments || CAN_user_tools_import_patrons || CAN_user_tools_edit_notices || CAN_user_tools_edit_notice_status_triggers || CAN_user_tools_label_creator || CAN_user_tools_delete_anonymize_patrons || CAN_user_tools_edit_patrons || CAN_user_tools_batch_extend_due_dates || CAN_user_tools_moderate_tags || CAN_user_tools_rotating_collections || ( CAN_user_tools_batch_upload_patron_images && Koha.Preference('patronimages') ) ) %] + [% IF ( CAN_user_tools_manage_patron_lists || CAN_user_clubs || CAN_user_tools_moderate_comments || CAN_user_tools_import_patrons || CAN_user_tools_edit_notices || CAN_user_tools_edit_notice_status_triggers || CAN_user_tools_label_creator || CAN_user_tools_delete_anonymize_patrons || CAN_user_tools_edit_patrons || CAN_user_tools_batch_extend_due_dates || CAN_user_tools_batch_modify_holds || CAN_user_tools_moderate_tags || CAN_user_tools_rotating_collections || ( CAN_user_tools_batch_upload_patron_images && Koha.Preference('patronimages') ) ) %]

    Patrons and circulation

    [% END %]
    @@ -88,6 +88,11 @@
    Modify the due date checkouts in batch
    [% END %] + [% IF ( CAN_user_tools_batch_modify_holds ) %] +
    Batch modify holds
    +
    Modify holds in batch
    + [% END %] + [% IF ( CAN_user_tools_moderate_tags ) %]
    Tags diff --git a/tools/batch_modify_holds.pl b/tools/batch_modify_holds.pl new file mode 100755 index 0000000000..c73b1f332e --- /dev/null +++ b/tools/batch_modify_holds.pl @@ -0,0 +1,107 @@ +#!/usr/bin/perl + +# This file is part of Koha. +# +# Copyright 2024 Koha Development Team +# +# Koha is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3 +# of the License, or (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General +# Public License along with Koha; if not, see +# + +use Modern::Perl; +use CGI; + +use JSON qw( to_json ); + +use C4::Auth qw( get_template_and_user ); +use C4::Output qw( output_html_with_http_headers ); + +use Koha::DateUtils qw( dt_from_string ); +use Koha::Holds; + +my $input = CGI->new; +my $op = $input->param('op') // q|cud-form|; + +my ( $template, $loggedinuser, $cookie ) = get_template_and_user( + { + template_name => 'tools/batch_modify_holds.tt', + query => $input, + type => "intranet", + flagsrequired => { tools => 'batch_modify_holds' }, + } +); + +my @hold_ids; + +if ( $op eq 'cud-form' ) { + my $reserve_ids_list = $input->param('reserve_ids_list') || undef; + if ($reserve_ids_list) { + my @reserve_ids = split /\n/, $reserve_ids_list; + $template->param( reserve_ids_list => to_json( \@reserve_ids ), ); + } + $template->param( view => 'cud-form', ); +} elsif ( $op eq 'cud-modify' ) { + my $new_expiration_date = $input->param('new_expiration_date'); + my $new_pickup_loc = $input->param('new_pickup_loc'); + my $new_suspend_status = $input->param('new_suspend_status'); + my $new_suspend_date = $input->param('new_suspend_date'); + my $new_hold_note = $input->param('new_hold_note'); + my $clear_hold_notes = $input->param('clear_hold_notes'); + + @hold_ids = $input->multi_param('hold_id'); + + my $holds_to_update = + Koha::Holds->search( { reserve_id => { -in => \@hold_ids } }, { join => [ "item", "biblio" ] } ); + + while ( my $hold = $holds_to_update->next ) { + + if ($new_expiration_date) { + $hold->expirationdate($new_expiration_date)->store; + } + + if ( $new_pickup_loc && ( $hold->branchcode ne $new_pickup_loc ) ) { + $hold->branchcode($new_pickup_loc)->store; + } + + if ( $new_suspend_status && $new_suspend_status ne "" && !$hold->is_found ) { + $hold->suspend(1)->store; + if ($new_suspend_date) { + $hold->suspend_until($new_suspend_date)->store; + } else { + $hold->suspend_until(undef)->store; + } + } elsif ( !$new_suspend_status && $new_suspend_date ) { + $hold->suspend(1)->store; + $hold->suspend_until($new_suspend_date)->store; + } else { + $hold->suspend(0)->store; + $hold->suspend_until(undef)->store; + } + + if ($new_hold_note) { + $hold->reservenotes($new_hold_note)->store; + } + + if ($clear_hold_notes) { + $hold->reservenotes(undef)->store; + } + } + + $template->param( + updated_holds => to_json( \@hold_ids ), + view => 'report', + ); + +} + +output_html_with_http_headers $input, $cookie, $template->output;