From 5401135f4322223721e0fcd61d04efd3029066ee Mon Sep 17 00:00:00 2001 From: Aleisha Amohia Date: Fri, 8 Oct 2021 16:09:11 +1300 Subject: [PATCH] Bug 31415: Script to automate converting holds to recalls This patch adds a script which can be used to automatically convert the oldest hold on a record to a recall, if there are a specified minimum number of holds on the record. To test: 1) Enable UseRecalls and configure circulation rules relevant to recalls. Keep the 'on shelf recalls allowed' setting to 'any' for the sake of testing ('all' would require all items to be checked out for the hold to be converted to a recall) 2) Check out items from multiple records (at least 2 different records) to Patron A. 3) Place multiple holds on each record (at least 2 holds). 4) Place multiple holds on another record which has no items checked out. 5) We now have multiple records where the oldest hold is eligible for recall, plus a record where the oldest hold is NOT eligible for recall (because no items are checked out). 6) In your terminal, get into the shell and run the script. -v means verbose and will print the holds that are converted into recalls. --min 1 means there must be more than 1 hold on the record to be considered. sudo koha-shell INSTANCE perl misc/cronjobs/recalls/convert_holds_to_recalls.pl -v --min 1 7) Confirm that, for the records where items are checked out and there are multiple holds, the oldest hold was converted into a recall 8) Confirm that, for the record where no items are checked out, the holds all remain and not converted into a recall. 9) Confirm documentation for the script looks good perldoc misc/cronjobs/recalls/convert_holds_to_recalls.pl Sponsored-by: Auckland University of Technology Signed-off-by: David Nind --- .../recalls/convert_holds_to_recalls.pl | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100755 misc/cronjobs/recalls/convert_holds_to_recalls.pl diff --git a/misc/cronjobs/recalls/convert_holds_to_recalls.pl b/misc/cronjobs/recalls/convert_holds_to_recalls.pl new file mode 100755 index 0000000000..79bd0f9bc0 --- /dev/null +++ b/misc/cronjobs/recalls/convert_holds_to_recalls.pl @@ -0,0 +1,135 @@ +#!/usr/bin/perl + +# Copyright 2021 Aleisha Amohia +# +# This file is part of Koha. +# +# 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 Getopt::Long; + +BEGIN { + # find Koha's Perl modules + # test carefully before changing this + use FindBin; + eval { require "$FindBin::Bin/../kohalib.pl" }; +} + +use Koha::Script -cron; +use Koha::DateUtils qw( dt_from_string ); +use Koha::Recalls; +use C4::Log; + +cronlogaction(); + +=head1 NAME + +convert_holds_to_recalls.pl + +=head1 SYNOPSIS + + convert_holds_to_recalls.pl [-v] [--min X] + +This script converts holds to recalls when a record has a set minimum number of holds placed. + +If a record is found to have the specified minimum number of holds, the script will find the oldest hold and convert it to a recall, as long as it would be a legal recall. + +It will only convert the single oldest hold. Once converted, the script will move on to the next record, it will not continue to convert holds on this record. + + Options: + -v verbose + --min X minimum number of holds + +=head1 OPTIONS + +=over 8 + +=item B<-v> | B<--verbose> + +Verbose. Without this flag set, only fatal errors are reported. + +=item B<-m> | B<--min> + +The minimum number of holds that may exist on a record for it to be selected for conversion + +=back + +=cut + +my $min = 5; +my $verbose; + +GetOptions( + 'min|m=i' => \$min, + 'verbose|v' => \$verbose +) or pod2usage(1); + +# get holds where there is more than $min holds on one biblio +my @bib_holds = Koha::Holds->search({}, { + select => [ + 'biblionumber', + { count => 'biblionumber', -as => 'bibcount' } + ], + group_by => 'biblionumber', + having => { 'bibcount' => { '>=', $min } }, +})->as_list; + +my $count = 0; +foreach my $bib ( @bib_holds ) { + $bib = $bib->unblessed; + if ( $bib->{bibcount} >= $min ) { + # If there are $min or more holds on the same record, convert the oldest hold to a recall + + my @holds = Koha::Holds->search({ biblionumber => $bib->{biblionumber} }, { order_by => { -asc => 'reservedate' } })->as_list; + my $hold_to_convert = $holds[0]; + foreach my $res ( @holds ) { + if ( dt_from_string($res->reservedate) < dt_from_string($hold_to_convert->reservedate) ) { + $hold_to_convert = $res; + } + } + + my $patron = Koha::Patrons->find( $hold_to_convert->borrowernumber ); + my $biblio = Koha::Biblios->find( $hold_to_convert->biblionumber ); + my $item; + my $can_convert; + if ( $hold_to_convert->item_level_hold ) { + $item = Koha::Items->find( $hold_to_convert->itemnumber ); + if ( $item->can_be_recalled({ patron => $patron, hold_convert => 1 }) ) { + $can_convert = 1; + } + } else { + if ( $biblio->can_be_recalled({ patron => $patron, hold_convert => 1 }) ) { + $can_convert = 1; + } + } + if ( $can_convert ) { + my ( $recall, $due_interval, $due_date ) = Koha::Recalls->add_recall({ + patron => $patron, + biblio => $biblio, + branchcode => $hold_to_convert->branchcode, + item => $item, + expirationdate => $hold_to_convert->expirationdate, + interface => 'commandline', + }); + $hold_to_convert->cancel({ cancellation_reason => 'RECALLED' }); + $count++; + if ( $verbose ) { + my $hold_id = $hold_to_convert->hold_id; + my $biblionumber = $hold_to_convert->biblionumber; + print "$count. Hold converted to recall (hold_id: $hold_id, biblionumber: $biblionumber).\n"; + } + } + } +} -- 2.30.2