@@ -, +, @@
of titles
--- a/C4/Reserves.pm
+++ a/C4/Reserves.pm
@@ -147,6 +147,10 @@ BEGIN {
IsItemOnHoldAndFound
GetMaxPatronHoldsForRecord
+
+ &AddReserveGroup
+ &DeleteReserveGroup
+ &GetReserveGroupReserves
);
@EXPORT_OK = qw( MergeHolds );
}
@@ -171,7 +175,8 @@ sub AddReserve {
my (
$branch, $borrowernumber, $biblionumber, $bibitems,
$priority, $resdate, $expdate, $notes,
- $title, $checkitem, $found, $itemtype
+ $title, $checkitem, $found, $itemtype,
+ $reserve_group_id
) = @_;
my $dbh = C4::Context->dbh;
@@ -211,6 +216,7 @@ sub AddReserve {
waitingdate => $waitingdate,
expirationdate => $expdate,
itemtype => $itemtype,
+ reserve_group_id => $reserve_group_id,
}
)->store();
@@ -1350,6 +1356,16 @@ sub ModReserveAffect {
}
$hold->store();
+ if ($hold->reserve_group_id) {
+ # Delete other reserves from same group
+ $dbh->do(q{
+ DELETE FROM reserves
+ WHERE reserve_group_id = ?
+ AND reserve_id != ?
+ }, undef, $hold->reserve_group_id, $hold->reserve_id);
+ DeleteReserveGroup($hold->reserve_group_id);
+ }
+
_koha_notify_reserve( $itemnumber, $borrowernumber, $biblionumber )
if ( !$transferToDo && !$already_on_shelf );
@@ -1432,6 +1448,7 @@ sub GetReserveInfo {
reminderdate,
priority,
found,
+ reserve_group_id,
firstname,
surname,
phone,
@@ -2546,6 +2563,60 @@ sub GetHoldRule {
return $sth->fetchrow_hashref();
}
+=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);
+}
+
+=head2 GetReserveGroupReserves
+
+ my @reserves = GetReserveGroupReserves($reserve_group_id);
+
+Fetch all reserve from a reserve group.
+
+=cut
+
+sub GetReserveGroupReserves {
+ my ($reserve_group_id) = @_;
+
+ my $dbh = C4::Context->dbh;
+
+ my $reserves = $dbh->selectall_arrayref(q{
+ SELECT * FROM reserves
+ WHERE reserve_group_id = ?
+ }, { Slice => {} }, $reserve_group_id);
+
+ return () unless defined $reserves;
+
+ return @$reserves;
+}
+
=head1 AUTHOR
Koha Development Team
--- a/Koha/Template/Plugin/Biblio.pm
+++ a/Koha/Template/Plugin/Biblio.pm
@@ -32,4 +32,12 @@ sub HoldsCount {
return $holds->count();
}
+sub Get {
+ my ($self, $biblionumber) = @_;
+
+ my $biblio = Koha::Biblios->find($biblionumber);
+
+ return $biblio;
+}
+
1;
--- a/circ/pendingreserves.pl
+++ a/circ/pendingreserves.pl
@@ -118,6 +118,7 @@ if ( $run_report ) {
reminderdate,
max(priority) as priority,
reserves.found,
+ reserves.reserve_group_id,
biblio.title,
biblio.author,
count(DISTINCT items.itemnumber) as icount,
@@ -167,7 +168,8 @@ if ( $run_report ) {
biblionumber => $data->{biblionumber},
statusw => ( $data->{found} eq "W" ),
statusf => ( $data->{found} eq "F" ),
- holdingbranches => [split('\|', $data->{l_holdingbranch})],,
+ reserve_group_id => $data->{reserve_group_id},
+ holdingbranches => [split('\|', $data->{l_holdingbranch})],
branch => $data->{l_branch},
itemcallnumber => $data->{l_itemcallnumber},
enumchron => $data->{l_enumchron},
--- a/installer/data/mysql/atomicupdate/bug_15516.sql
+++ a/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_6 FOREIGN KEY (reserve_group_id) REFERENCES reserve_group (reserve_group_id) ON DELETE SET NULL ON UPDATE CASCADE;
--- a/installer/data/mysql/kohastructure.sql
+++ a/installer/data/mysql/kohastructure.sql
@@ -1868,6 +1868,7 @@ CREATE TABLE `reserves` ( -- information related to holds/reserves in Koha
`suspend` BOOLEAN NOT NULL DEFAULT 0,
`suspend_until` DATETIME NULL DEFAULT NULL,
`itemtype` VARCHAR(10) NULL DEFAULT NULL, -- If record level hold, the optional itemtype of the item the patron is requesting
+ `reserve_group_id` int unsigned NULL DEFAULT NULL, -- Id used on reservations spanning multiple titles
PRIMARY KEY (`reserve_id`),
KEY priorityfoundidx (priority,found),
KEY `borrowernumber` (`borrowernumber`),
@@ -1879,7 +1880,18 @@ 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 (`itemtype`) REFERENCES `itemtypes` (`itemtype`) ON DELETE CASCADE ON UPDATE CASCADE
+ CONSTRAINT `reserves_ibfk_5` FOREIGN KEY (`itemtype`) REFERENCES `itemtypes` (`itemtype`) ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT `reserves_ibfk_6` 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;
--
--- a/koha-tmpl/intranet-tmpl/prog/en/includes/reserve-group-modal.inc
+++ a/koha-tmpl/intranet-tmpl/prog/en/includes/reserve-group-modal.inc
@@ -0,0 +1,27 @@
+
+
+
+
Reserve group
+
+
+
Loading
+
+
+
+
+
--- a/koha-tmpl/intranet-tmpl/prog/en/includes/strings.inc
+++ a/koha-tmpl/intranet-tmpl/prog/en/includes/strings.inc
@@ -40,5 +40,7 @@
var SUSPEND_HOLD_ERROR_NOT_FOUND = _("Unable to suspend hold, hold not found");
var RESUME_HOLD_ERROR_NOT_FOUND = _("Unable to resume, hold not found");
var CURRENT = _(" (current) ");
+ var PART_OF_A = _("(part of a %s)");
+ var RESERVE_GROUP = _("reserve group");
//]]>
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt
+++ a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt
@@ -1002,4 +1002,5 @@ No patron matched [% message | html %]
You have already submitted a barcode, please wait for the checkout to process...
+[% INCLUDE 'reserve-group-modal.inc' %]
[% INCLUDE 'intranet-bottom.inc' %]
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/pendingreserves.tt
+++ a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/pendingreserves.tt
@@ -112,10 +112,16 @@ $(document).ready(function() {
+ [% END %]
+ [% INCLUDE 'intranet-bottom.inc' %]
--- a/koha-tmpl/intranet-tmpl/prog/js/holds.js
+++ a/koha-tmpl/intranet-tmpl/prog/js/holds.js
@@ -42,6 +42,12 @@ $(document).ready(function() {
title += " - " + oObj.itemnotes + ""
}
+ if (oObj.reserve_group_id) {
+ title += ' ';
+ var link = '' + RESERVE_GROUP +''
+ title += '' + PART_OF_A.format(link) + '';
+ }
+
return title;
}
},
--- a/reserve/placerequest.pl
+++ a/reserve/placerequest.pl
@@ -50,6 +50,7 @@ my $title = $input->param('title');
my $checkitem = $input->param('checkitem');
my $expirationdate = $input->param('expiration_date');
my $itemtype = $input->param('itemtype') || undef;
+my $requestany = $input->param('requestany');
my $borrower = GetMember( 'borrowernumber' => $borrowernumber );
@@ -83,6 +84,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;
@@ -106,8 +112,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, $itemtype,
+ $reserve_group_id);
} else {
# place a request on 1st available
for ( my $i = 0 ; $i < $holds_to_place_count ; $i++ ) {
--- a/reserve/request.pl
+++ a/reserve/request.pl
@@ -578,6 +578,7 @@ foreach my $biblionumber (@biblionumbers) {
$reserve{'reserve_id'} = $res->reserve_id();
$reserve{itemtype} = $res->itemtype();
$reserve{branchcode} = $res->branchcode();
+ $reserve{'reserve_group_id'} = $res->reserve_group_id;
push( @reserveloop, \%reserve );
}
--- a/reserve/reserve-group.pl
+++ a/reserve/reserve-group.pl
@@ -0,0 +1,42 @@
+#!/usr/bin/env perl
+
+# 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 CGI qw( -utf8 );
+
+use C4::Auth;
+use C4::Output;
+use C4::Reserves;
+
+my $cgi = new CGI;
+my ($template, $loggedinuser, $cookie) = get_template_and_user({
+ template_name => "reserve/reserve-group.tt",
+ query => $cgi,
+ type => "intranet",
+ authnotrequired => 0,
+ flagsrequired => { circulate => 'circulate_remaining_permissions' },
+});
+
+my $reserve_group_id = $cgi->param('reserve_group_id');
+my @reserves = GetReserveGroupReserves($reserve_group_id);
+
+$template->param(
+ reserve_group_id => $reserve_group_id,
+ reserves => \@reserves,
+);
+
+output_html_with_http_headers $cgi, $cookie, $template->output;
--- a/svc/holds
+++ a/svc/holds
@@ -101,6 +101,7 @@ while ( my $h = $holds_rs->next() ) {
waiting_here => $h->branch()->branchcode() eq $branch,
priority => $h->priority(),
itemtype_limit => $itemtype_limit,
+ reserve_group_id => $h->reserve_group_id,
subtitle => GetRecordValue(
'subtitle', GetMarcBiblio($biblionumber),
GetFrameworkCode($biblionumber)
--