@@ -, +, @@ Requires embedding volume in hold API --- Koha/Hold.pm | 16 ++++ Koha/Holds.pm | 3 + .../prog/en/includes/holds_table.inc | 2 + .../prog/en/modules/reserve/request.tt | 78 +++++++++++++++++-- reserve/request.pl | 7 ++ t/db_dependent/Koha/Holds.t | 28 ++++++- 6 files changed, 126 insertions(+), 8 deletions(-) --- a/Koha/Hold.pm +++ a/Koha/Hold.pm @@ -282,6 +282,22 @@ sub biblio { return $self->{_biblio}; } +=head3 volume + +Returns the related Koha::Biblio::Volume object for this hold + +=cut + +sub volume { + my ($self) = @_; + + my $volume_rs = $self->_result->volume; + + return unless $volume_rs; + + return Koha::Biblio::Volume->_new_from_dbic($volume_rs); +} + =head3 item Returns the related Koha::Item object for this Hold --- a/Koha/Holds.pm +++ a/Koha/Holds.pm @@ -86,6 +86,9 @@ sub forced_hold_level { my $item_level_count = $self->search( { itemnumber => { '!=' => undef } } )->count(); return 'item' if $item_level_count > 0; + my $volume_level_count = $self->search( { volume_id => { '!=' => undef } } )->count(); + return 'volume' if $volume_level_count > 0; + my $record_level_count = $self->search( { itemnumber => undef } )->count(); return 'record' if $record_level_count > 0; --- a/koha-tmpl/intranet-tmpl/prog/en/includes/holds_table.inc +++ a/koha-tmpl/intranet-tmpl/prog/en/includes/holds_table.inc @@ -163,6 +163,8 @@ [% ELSE %] [% IF hold.itemtype %] Next available [% ItemTypes.GetDescription( hold.itemtype ) | html %] item + [% ELSIF hold.object.volume_id %] + Next available item from volume [% hold.object.volume.description | html %] [% ELSE %] Next available [% END %] --- a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt @@ -465,7 +465,7 @@ [% UNLESS ( multi_hold ) %]
  • - [% IF force_hold_level == 'item' %] + [% IF force_hold_level == 'item' || force_hold_level == 'volume' %] [% ELSIF force_hold_level == 'record' %] @@ -485,6 +485,41 @@ [% ELSE %] [% END %] + + + [% FOREACH bibitemloo IN bibitemloop %] + [% IF Koha.Preference('EnableVolumeHolds') && bibitemloo.volumes.count %] + + + [% IF bibitemloo.force_hold_level == 'record' # Patron has placed a record level hold previously for this record %] + + + Hold must be record level + + [% ELSIF bibitemloo.force_hold_level == 'item' # Patron has placed an item level hold previously for this record %] + + + Hold must be item level + + [% ELSE %] + [% FOREACH v IN bibitemloo.volumes %] + [% IF v.items %] +
  • + + +
  • + [% END %] + [% END %] + [% END %] + [% END %] + [% END %] + + [% END # /UNLESS multi_hold %] @@ -533,6 +568,9 @@ Item type [% END %] Barcode + [% IF Koha.Preference('EnableVolumeHolds') && bibitemloo.volumes.count %] + Volume + [% END %] Home library Last location [% IF itemdata_ccode %] @@ -558,6 +596,11 @@ Hold must be record level + [% ELSIF itemloo.force_hold_level == 'volume' # Patron has placed a volume level hold previously for this record %] + + + Hold must be volume level + [% ELSIF ( itemloo.available ) %] [% ELSIF ( itemloo.override ) %] @@ -605,6 +648,11 @@ [% itemloo.barcode | html %] + [% IF Koha.Preference('EnableVolumeHolds') && bibitemloo.volumes.count %] + + [% itemloo.object.volume.description | html %] + + [% END %] [% Branches.GetName( itemloo.homebranch ) | html %] @@ -1038,6 +1086,8 @@ }; if($('input[name="checkitem"]:checked').length) data.item_id = $('input[name="checkitem"]:checked').val(); + if($('input[name="volume_id"]:checked').length) + data.volume_id = $('input[name="volume_id"]:checked').val(); if($('input[name="borrowernumber"]').length) data.patron_id = $('input[name="borrowernumber"]').val(); if($('textarea[name="notes"]').length) @@ -1057,12 +1107,14 @@ const count = $('input[name="holds_to_place_count"]').length?$('input[name="holds_to_place_count"]').val():1; biblionumbers.forEach(function(biblionumber) { data.biblio_id = biblionumber; + console.log(data); let options = { url: $t.attr('action'), method: $t.attr('method').toUpperCase(), contentType: 'application/json', data: JSON.stringify(data) }; + console.log(options); for(let i = 0; i < count; i++) { $.ajax(options) .then(function(result) { @@ -1087,8 +1139,8 @@ }); [% UNLESS ( multi_hold ) %] - $("#hold-request-form").on("submit", function(){ - return check(); + $("#hold-request-form [type='submit']").on("click", function(e){ + return check(e); }); [% ELSE %] $("#hold-request-form").on("submit", function(){ @@ -1098,7 +1150,7 @@ }); - function check() { + function check(e) { var msg = ""; var count_reserv = 0; @@ -1117,6 +1169,8 @@ } } + count_reserv += $("input[name='volume_id']:checked").length; + if (document.form.requestany.checked == true){ count_reserv++ ; } @@ -1129,6 +1183,7 @@ $('#hold-request-form').preventDoubleFormSubmit(); return(true); } else { + e.preventDefault(); alert(msg); return(false); } @@ -1181,14 +1236,14 @@ }); $("#requestany").click(function() { if(this.checked){ - $("input[name=checkitem]").each(function() { + $("input[name=checkitem], input[name='volume_id']").each(function() { $(this).prop("checked", false); }); } }); - $("input[name=checkitem]").click(function() { + $("input[name=checkitem], input[name='volume_id']").click(function() { onechecked = 0; - $("input[name=checkitem]").each(function() { + $("input[name=checkitem], input[name='volume_id']").each(function() { if(this.checked){ onechecked = 1; } @@ -1260,6 +1315,15 @@ [% END %] [% END %] + [% IF Koha.Preference('EnableVolumeHolds') %] + $(':radio[name="volume_id"]').change(function(){ + $(':radio[name="checkitem"]').attr('checked', false); + }); + $(':radio[name="checkitem"]').change(function(){ + $(':radio[name="volume_id"]').attr('checked', false); + }); + [% END %] + }); [% END %] --- a/reserve/request.pl +++ a/reserve/request.pl @@ -490,6 +490,7 @@ foreach my $biblionumber (@biblionumbers) { # checking reserve my $item_object = Koha::Items->find( $itemnumber ); + $item->{object} = $item_object; my $holds = $item_object->current_holds; if ( my $first_hold = $holds->next ) { my $p = Koha::Patrons->find( $first_hold->borrowernumber ); @@ -617,6 +618,12 @@ foreach my $biblionumber (@biblionumbers) { } $template->param( hiddencount => $hiddencount); + if ( C4::Context->preference('EnableVolumeHolds') ) { + my $volumes = Koha::Biblio::Volumes->search( + { biblionumber => $biblionumber } ); + $biblioitem->{volumes} = $volumes; + } + push @bibitemloop, $biblioitem; } --- a/t/db_dependent/Koha/Holds.t +++ a/t/db_dependent/Koha/Holds.t @@ -25,6 +25,7 @@ use Test::Warn; use C4::Reserves; use Koha::Holds; use Koha::Database; +use Koha::Biblio::Volumes; use t::lib::Mocks; use t::lib::TestBuilder; @@ -35,7 +36,7 @@ $schema->storage->txn_begin; my $builder = t::lib::TestBuilder->new; subtest 'cancel' => sub { - plan tests => 12; + plan tests => 13; my $biblioitem = $builder->build_object( { class => 'Koha::Biblioitems' } ); my $library = $builder->build_object( { class => 'Koha::Libraries' } ); my $itemtype = $builder->build_object( { class => 'Koha::ItemTypes', value => { rentalcharge => 0 } } ); @@ -151,6 +152,31 @@ subtest 'cancel' => sub { is( $hold_old->found, 'W', 'The found column should have been kept and a hold is cancelled' ); }; + subtest 'Test Koha::Hold::volume' => sub { + plan tests => 1; + my $patron = $builder->build_object( { class => 'Koha::Patrons' } ); + my $volume = $builder->build_object( + { + class => 'Koha::Biblio::Volumes', + value => { biblionumber => $item->biblionumber } + } + ); + my $reserve_id = C4::Reserves::AddReserve( + $library->branchcode, $patron->borrowernumber, + $item->biblionumber, '', + 1, undef, + undef, '', + "title for fee", $item->itemnumber, + 'W', undef, + $volume->id + ); + + my $hold = Koha::Holds->find($reserve_id); + is( $hold->volume_id, $volume->id, + 'Koha::Hold::volume returns the correct volume' ); + }; + + subtest 'HoldsLog' => sub { plan tests => 2; my $patron = $builder->build_object({ class => 'Koha::Patrons' }); --