From e7372533279ad8b400a6898292ee24ffca65ae39 Mon Sep 17 00:00:00 2001 From: Kyle Hall Date: Fri, 3 Jun 2022 06:33:25 -0400 Subject: [PATCH] Bug 24860: Add ability to select an item group when placing a hold Signed-off-by: Andrew Fuerste-Henry Signed-off-by: Rebecca Coert --- C4/Reserves.pm | 1 + Koha/Hold.pm | 14 ++++ Koha/Holds.pm | 3 + .../prog/en/includes/holds_table.inc | 2 + .../prog/en/modules/reserve/request.tt | 80 ++++++++++++++++++- reserve/placerequest.pl | 2 + reserve/request.pl | 4 + t/db_dependent/Koha/Holds.t | 29 ++++++- 8 files changed, 130 insertions(+), 5 deletions(-) diff --git a/C4/Reserves.pm b/C4/Reserves.pm index 332aa1d8b15..b3dbb7bd0ae 100644 --- a/C4/Reserves.pm +++ b/C4/Reserves.pm @@ -163,6 +163,7 @@ BEGIN { itemnumber => $itemnumber, found => $found, itemtype => $itemtype, + item_gorup_id => $item_group_id } ); diff --git a/Koha/Hold.pm b/Koha/Hold.pm index 68d0c8581d6..cb10e4b65af 100644 --- a/Koha/Hold.pm +++ b/Koha/Hold.pm @@ -471,6 +471,20 @@ sub item { return $self->{_item}; } +=head3 item_group + +Returns the related Koha::Biblio::ItemGroup object for this Hold + +=cut + +sub item_group { + my ($self) = @_; + + my $item_group_rs = $self->_result->item_group; + return unless $item_group_rs; + return Koha::Biblio::ItemGroup->_new_from_dbic($item_group_rs); +} + =head3 branch Returns the related Koha::Library object for this Hold diff --git a/Koha/Holds.pm b/Koha/Holds.pm index 7d070f8513a..576818ffef5 100644 --- a/Koha/Holds.pm +++ b/Koha/Holds.pm @@ -85,6 +85,9 @@ sub forced_hold_level { my $item_level_count = $self->search( { itemnumber => { '!=' => undef } } )->count(); return 'item' if $item_level_count > 0; + my $item_group_level_count = $self->search( { item_group_id => { '!=' => undef } } )->count(); + return 'item_group' if $item_group_level_count > 0; + my $record_level_count = $self->search( { itemnumber => undef } )->count(); return 'record' if $record_level_count > 0; diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/holds_table.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/holds_table.inc index be1d4fe101b..844e00acd33 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/holds_table.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/holds_table.inc @@ -176,6 +176,8 @@ [%- ELSE -%] [%- IF hold.itemtype -%] Next available [% ItemTypes.GetDescription( hold.itemtype ) | html %] item + [%- ELSIF hold.object.item_group -%] + Next available item from group [% hold.object.item_group.description | html %] [%- ELSE -%] Next available [%- END -%] 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 3a8b7909068..9cb7f5b22f5 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt @@ -596,7 +596,7 @@ [% UNLESS ( multi_hold ) %]
  • - [% IF force_hold_level == 'item' %] + [% IF force_hold_level == 'item' || force_hold_level == 'item_group' %] [% ELSIF force_hold_level == 'record' %] @@ -655,6 +655,52 @@ [% END %] + + [% IF Koha.Preference('EnableItemGroupHolds') && biblio.object.item_groups.count %] +

    + Hold next available item from an item group + [% IF force_hold_level == 'item_group' %] + (Required) + [% END %] +

    + + [% IF force_hold_level == 'record' # Patron has placed a record level hold previously for this record %] + + + Hold must be record level + + [% ELSIF force_hold_level == 'item' # Patron has placed an item level hold previously for this record %] + + + Hold must be item level + + [% ELSE %] + + + + + + + + + [% FOREACH g IN biblio.object.item_groups.search({}, { order_by => ['display_order'] }) %] + [% IF g.items %] + + + + + [% END %] + [% END %] + +
    HoldItem group
    + + + +
    + [% END %] + [% END %] + +

    Place a hold on a specific item [% IF force_hold_level == 'item' %] @@ -671,6 +717,9 @@ Item type [% END %] Barcode + [% IF Koha.Preference('EnableItemGroupHolds') && biblio.object.item_groups.count %] + Item group + [% END %] Home library Last location [% IF itemdata_ccode %] @@ -695,6 +744,11 @@ Hold must be record level + [% ELSIF force_hold_level == 'item_group' %] + + + Hold must be item group level + [% ELSIF ( itemloo.available ) %] [% ELSIF ( itemloo.override ) %] @@ -764,6 +818,11 @@ [% itemloo.barcode | html %] + [% IF Koha.Preference('EnableItemGroupHolds') && biblio.object.item_groups.count %] + + [% itemloo.object.item_group.description | html %] + + [% END %] [% Branches.GetName( itemloo.homebranch ) | html %] @@ -1330,6 +1389,8 @@ }; if($('input[name="checkitem"]:checked').length) data.item_id = $('input[name="checkitem"]:checked').val(); + if($('input[name="item_group_id"]:checked').length) + data.item_group_id = $('input[name="item_group_id"]:checked').val(); if($('input[name="borrowernumber"]').length) data.patron_id = $('input[name="borrowernumber"]').val(); if($('textarea[name="notes"]').length) @@ -1375,8 +1436,8 @@ }); [% UNLESS ( multi_hold ) %] - $("#hold-request-form").on("submit", function(){ - return check($(this)); + $("#hold-request-form").on("submit", function(e){ + return check(e, $(this)); }); [% ELSE %] $("#hold-request-form").on("submit", function(){ @@ -1420,7 +1481,7 @@ }); }); - function check( table ) { + function check( e, table ) { var msg = ""; @@ -1451,6 +1512,7 @@ $('#hold-request-form').preventDoubleFormSubmit(); return(true); } else { + e.preventDefault(); alert(msg); return(false); } @@ -1604,6 +1666,16 @@ stickyClass: "floating" }); + [% IF Koha.Preference('EnableItemGroupHolds') %] + $(':radio[name="item_group_id"]').change(function(){ + $(':radio[name="checkitem"]').prop('checked', false); + }); + + $(':radio[name="checkitem"]').change(function(){ + $(':radio[name="item_group_id"]').prop('checked', false); + }); + [% END %] + if(!localStorage.selectedHolds || document.referrer.replace(/\?.*/, '') !== document.location.origin+document.location.pathname) { localStorage.selectedHolds = []; } diff --git a/reserve/placerequest.pl b/reserve/placerequest.pl index 0fc7361b73f..a253fb55473 100755 --- a/reserve/placerequest.pl +++ b/reserve/placerequest.pl @@ -45,6 +45,7 @@ my $startdate = $input->param('reserve_date') || ''; my @rank = $input->multi_param('rank-request'); my $title = $input->param('title'); my $checkitem = $input->param('checkitem'); +my $item_group_id = $input->param('item_group_id'); my $expirationdate = $input->param('expiration_date'); my $itemtype = $input->param('itemtype') || undef; my $non_priority = $input->param('non_priority'); @@ -140,6 +141,7 @@ if ( $patron ) { found => $found, itemtype => $itemtype, non_priority => $non_priority, + item_group_id => $item_group_id, } ); } diff --git a/reserve/request.pl b/reserve/request.pl index b6bdb0baff8..95ac2a8098f 100755 --- a/reserve/request.pl +++ b/reserve/request.pl @@ -301,12 +301,15 @@ if ( ( $findborrower && $borrowernumber_hold || $findclub && $club_hold ) my %biblioloopiter = (); my $biblio = Koha::Biblios->find( $biblionumber ); + unless ($biblio) { $biblioloopiter{noitems} = 1; $template->param('nobiblio' => 1); last; } + $biblioloopiter{object} = $biblio; + if ( $patron ) { { # CanBookBeReserved my $canReserve = CanBookBeReserved( $patron->borrowernumber, $biblionumber ); @@ -399,6 +402,7 @@ if ( ( $findborrower && $borrowernumber_hold || $findclub && $club_hold ) for my $item_object ( @items ) { my $do_check; my $item = $item_object->unblessed; + $item->{object} = $item_object; if ( $patron ) { $do_check = $patron->do_check_for_previous_checkout($item) if $wants_check; if ( $do_check && $wants_check ) { diff --git a/t/db_dependent/Koha/Holds.t b/t/db_dependent/Koha/Holds.t index 6d47bf2a620..d18d822a8f8 100755 --- a/t/db_dependent/Koha/Holds.t +++ b/t/db_dependent/Koha/Holds.t @@ -19,12 +19,13 @@ use Modern::Perl; -use Test::More tests => 7; +use Test::More tests => 8; use Test::Warn; use C4::Circulation qw( AddIssue ); use C4::Reserves qw( AddReserve ModReserve ModReserveCancelAll ); use Koha::AuthorisedValueCategory; +use Koha::Biblio::ItemGroups; use Koha::Database; use Koha::DateUtils qw( dt_from_string ); use Koha::Holds; @@ -641,6 +642,32 @@ subtest 'set_waiting+patron_expiration_date' => sub { }; }; +subtest 'Test Koha::Hold::item_group' => sub { + plan tests => 1; + my $library = $builder->build_object( { class => 'Koha::Libraries' } ); + my $patron = $builder->build_object({ class => 'Koha::Patrons' }); + my $item = $builder->build_sample_item; + my $item_group = $builder->build_object( + { + class => 'Koha::Biblio::ItemGroups', + value => { biblionumber => $item->biblionumber } + } + ); + my $reserve_id = AddReserve( + { + branchcode => $library->branchcode, + borrowernumber => $patron->borrowernumber, + biblionumber => $item->biblionumber, + itemnumber => $item->itemnumber, + item_group_id => $item_group->id, + } + ); + + my $hold = Koha::Holds->find($reserve_id); + is( $hold->item_group_id, $item_group->id, + 'Koha::Hold::item_group returns the correct item_group' ); +}; + $schema->storage->txn_rollback; -- 2.30.2