From 17a177d041ee207dc7be39130557a4f45e81cfa9 Mon Sep 17 00:00:00 2001 From: Julian Maurice Date: Thu, 7 Jan 2016 14:14:18 +0100 Subject: [PATCH] Bug 15516: Allow to reserve first available item from a group of titles It can be useful, for instance, if a library have the same title from different publishers (so 1 title but several biblio records) but the user only wants a copy of the book, regardless of the publisher. This patch is a kind of "RFC-patch" as I'm not sure of how to implement that feature. It's obviously not finished, as I would like some feedback before going further. Test plan: 0. Run updatedatabase.pl and misc/devel/update_dbix_class_files.pl 1. Go to intranet search, display some results, click on some checkboxes and click on 'Place hold' button at the top of the results. 2. Enter a patron cardnumber and click Search 3. Check the box for 'Place a hold on the next available item' (it's usually hidden when placing a hold on multiple biblios) 4. Click on 'Place hold' 5. In the next screen you should see all the holds you placed with the additional text '(part of a reserve group)' in Details column. 6. Check in an item of one of the reserved biblios and confirm the hold 7. The hold status is changed to Waiting, and all other holds are deleted. Comments: - A column is added to the reserves table (reserve_group_id) to group the reserves that belong together, and an additional table (reserve_group) with a single column is used to generate an auto increment ID. I feel that something better can be done... - I don't know how to indicates in the interface that two or more reserves are only one request in reality. - I'm bad at naming things, and "reserve_group" should probably be something else. --- C4/Reserves.pm | 51 +++++++++++++++++++++- installer/data/mysql/atomicupdate/bug_15516.sql | 8 ++++ installer/data/mysql/kohastructure.sql | 12 +++++ .../prog/en/modules/reserve/request.tt | 11 +++-- reserve/placerequest.pl | 12 ++++- reserve/request.pl | 1 + 6 files changed, 88 insertions(+), 7 deletions(-) create mode 100644 installer/data/mysql/atomicupdate/bug_15516.sql diff --git a/C4/Reserves.pm b/C4/Reserves.pm index 7bb5d69..7ddad35 100644 --- a/C4/Reserves.pm +++ b/C4/Reserves.pm @@ -141,6 +141,9 @@ BEGIN { &GetReservesControlBranch IsItemOnHoldAndFound + + AddReserveGroup + DeleteReserveGroup ); @EXPORT_OK = qw( MergeHolds ); } @@ -165,7 +168,7 @@ sub AddReserve { my ( $branch, $borrowernumber, $biblionumber, $bibitems, $priority, $resdate, $expdate, $notes, - $title, $checkitem, $found + $title, $checkitem, $found, $reserve_group_id ) = @_; if ( Koha::Holds->search( { borrowernumber => $borrowernumber, biblionumber => $biblionumber } )->count() > 0 ) { @@ -205,7 +208,8 @@ sub AddReserve { itemnumber => $checkitem, found => $found, waitingdate => $waitingdate, - expirationdate => $expdate + expirationdate => $expdate, + reserve_group_id => $reserve_group_id, } )->store(); my $reserve_id = $hold->id(); @@ -1336,6 +1340,17 @@ sub ModReserveAffect { } $sth = $dbh->prepare($query); $sth->execute( $itemnumber, $borrowernumber,$biblionumber); + + if ($request->{reserve_group_id}) { + # Delete other reserves from same group + $dbh->do(q{ + DELETE FROM reserves + WHERE reserve_group_id = ? + AND reserve_id != ? + }, undef, $request->{reserve_group_id}, $request->{reserve_id}); + DeleteReserveGroup($request->{reserve_group_id}); + } + _koha_notify_reserve( $itemnumber, $borrowernumber, $biblionumber ) if ( !$transferToDo && !$already_on_shelf ); _FixPriority( { biblionumber => $biblionumber } ); if ( C4::Context->preference("ReturnToShelvingCart") ) { @@ -1415,6 +1430,7 @@ sub GetReserveInfo { reminderdate, priority, found, + reserve_group_id, firstname, surname, phone, @@ -2471,6 +2487,37 @@ sub IsItemOnHoldAndFound { return $found; } +=head2 AddReserveGroup + + my $reserve_group_id = AddReserveGroup(); + +Creates a new reserve group and returns its ID + +=cut + +sub AddReserveGroup { + my $dbh = C4::Context->dbh; + + $dbh->do('INSERT INTO reserve_group VALUES ()'); + return $dbh->last_insert_id(undef, undef, 'reserve_group', undef); +} + +=head2 DeleteReserveGroup + + DeleteReserveGroup($reserve_group_id); + +Delete a reserve group. Reserves that belong to this group are not removed. + +=cut + +sub DeleteReserveGroup { + my ($reserve_group_id) = @_; + + my $dbh = C4::Context->dbh; + my $query = 'DELETE FROM reserve_group WHERE reserve_group_id = ?'; + $dbh->do($query, undef, $reserve_group_id); +} + =head1 AUTHOR Koha Development Team diff --git a/installer/data/mysql/atomicupdate/bug_15516.sql b/installer/data/mysql/atomicupdate/bug_15516.sql new file mode 100644 index 0000000..efd761e --- /dev/null +++ b/installer/data/mysql/atomicupdate/bug_15516.sql @@ -0,0 +1,8 @@ +DROP TABLE IF EXISTS reserve_group; +CREATE TABLE reserve_group ( + reserve_group_id int unsigned NOT NULL AUTO_INCREMENT, + PRIMARY KEY (reserve_group_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +ALTER TABLE reserves ADD COLUMN reserve_group_id int unsigned NULL DEFAULT NULL; +ALTER TABLE reserves ADD CONSTRAINT reserves_ibfk_5 FOREIGN KEY (reserve_group_id) REFERENCES reserve_group (reserve_group_id) ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql index 431a541..57fecaa 100644 --- a/installer/data/mysql/kohastructure.sql +++ b/installer/data/mysql/kohastructure.sql @@ -1859,6 +1859,7 @@ CREATE TABLE `reserves` ( -- information related to holds/reserves in Koha `lowestPriority` tinyint(1) NOT NULL, `suspend` BOOLEAN NOT NULL DEFAULT 0, `suspend_until` DATETIME NULL DEFAULT NULL, + reserve_group_id int unsigned NULL DEFAULT NULL, PRIMARY KEY (`reserve_id`), KEY priorityfoundidx (priority,found), KEY `borrowernumber` (`borrowernumber`), @@ -1869,6 +1870,17 @@ CREATE TABLE `reserves` ( -- information related to holds/reserves in Koha CONSTRAINT `reserves_ibfk_2` FOREIGN KEY (`biblionumber`) REFERENCES `biblio` (`biblionumber`) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT `reserves_ibfk_3` FOREIGN KEY (`itemnumber`) REFERENCES `items` (`itemnumber`) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT `reserves_ibfk_4` FOREIGN KEY (`branchcode`) REFERENCES `branches` (`branchcode`) ON DELETE CASCADE ON UPDATE CASCADE + CONSTRAINT `reserves_ibfk_5` FOREIGN KEY (reserve_group_id) REFERENCES reserve_group (reserve_group_id) ON DELETE SET NULL ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- +-- Table structure for table reserve_group +-- + +DROP TABLE IF EXISTS reserve_group; +CREATE TABLE reserve_group ( + reserve_group_id int unsigned NOT NULL AUTO_INCREMENT, + PRIMARY KEY(reserve_group_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -- diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt index 3152f7f..106f321 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt @@ -423,13 +423,15 @@ function checkMultiHold() { Clear date - [% UNLESS ( multi_hold ) %]
  • - + [% IF multi_hold %] + + [% ELSE %] + + [% END %]
  • - [% END %] [% UNLESS ( multi_hold ) %] @@ -801,6 +803,9 @@ function checkMultiHold() { [% END %] [% END %] + [% IF reserveloo.reserve_group_id %] +
    (part of a reserve group)
    + [% END %] [% IF ( CAN_user_reserveforothers_modify_holds_priority ) %] diff --git a/reserve/placerequest.pl b/reserve/placerequest.pl index 80dcfdc..18835e0 100755 --- a/reserve/placerequest.pl +++ b/reserve/placerequest.pl @@ -50,6 +50,7 @@ my $title=$input->param('title'); my $borrower=GetMember('borrowernumber'=>$borrowernumber); my $checkitem=$input->param('checkitem'); my $expirationdate = $input->param('expiration_date'); +my $requestany = $input->param('requestany'); my $multi_hold = $input->param('multi_hold'); my $biblionumbers = $multi_hold ? $input->param('biblionumbers') : ($biblionumber . '/'); @@ -79,6 +80,11 @@ if (defined $checkitem && $checkitem ne ''){ if ($type eq 'str8' && $borrower){ + my $reserve_group_id; + if ($multi_hold && $requestany) { + $reserve_group_id = AddReserveGroup(); + } + foreach my $biblionumber (keys %bibinfos) { my $count=@bibitems; @bibitems=sort @bibitems; @@ -104,8 +110,10 @@ if ($type eq 'str8' && $borrower){ if ($multi_hold) { my $bibinfo = $bibinfos{$biblionumber}; - AddReserve($branch,$borrower->{'borrowernumber'},$biblionumber,[$biblionumber], - $bibinfo->{rank},$startdate,$expirationdate,$notes,$bibinfo->{title},$checkitem,$found); + AddReserve($branch, $borrower->{'borrowernumber'}, $biblionumber, + [$biblionumber], $bibinfo->{rank}, $startdate, $expirationdate, + $notes, $bibinfo->{title}, $checkitem, $found, + $reserve_group_id); } else { # place a request on 1st available AddReserve($branch,$borrower->{'borrowernumber'},$biblionumber,\@realbi,$rank[0],$startdate,$expirationdate,$notes,$title,$checkitem,$found); diff --git a/reserve/request.pl b/reserve/request.pl index 9b37f48..2f5dd09 100755 --- a/reserve/request.pl +++ b/reserve/request.pl @@ -562,6 +562,7 @@ foreach my $biblionumber (@biblionumbers) { $reserve{'suspend'} = $res->suspend(); $reserve{'suspend_until'} = $res->suspend_until(); $reserve{'reserve_id'} = $res->reserve_id(); + $reserve{'reserve_group_id'} = $res->reserve_group_id; if ( C4::Context->preference('IndependentBranches') && $flags->{'superlibrarian'} != 1 ) { $reserve{'branchloop'} = [ GetBranchDetail( $res->branchcode() ) ]; -- 1.9.1