Bugzilla – Attachment 181234 Details for
Bug 31698
Add ability to move a hold to a new bibliographic record/item
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 31698: Add ability to move holds to new items or new records
Bug-31698-Add-ability-to-move-holds-to-new-items-o.patch (text/plain), 26.61 KB, created by
Lucas Gass (lukeg)
on 2025-04-21 22:06:06 UTC
(
hide
)
Description:
Bug 31698: Add ability to move holds to new items or new records
Filename:
MIME Type:
Creator:
Lucas Gass (lukeg)
Created:
2025-04-21 22:06:06 UTC
Size:
26.61 KB
patch
obsolete
>From deedfbb6492cb5f5167b1f7c219796b1cfe21367 Mon Sep 17 00:00:00 2001 >From: Lucas Gass <lucas@bywatersolutions.com> >Date: Wed, 12 Mar 2025 21:31:35 +0000 >Subject: [PATCH] Bug 31698: Add ability to move holds to new items or new > records > >--- > Koha/Hold.pm | 61 ++++ > .../prog/en/includes/holds_table.inc | 10 +- > .../prog/en/modules/reserve/request.tt | 295 ++++++++++++++++++ > reserve/request.pl | 58 +++- > 4 files changed, 421 insertions(+), 3 deletions(-) > >diff --git a/Koha/Hold.pm b/Koha/Hold.pm >index b3bf4a02b76..f76c0189580 100644 >--- a/Koha/Hold.pm >+++ b/Koha/Hold.pm >@@ -178,6 +178,67 @@ sub delete { > return $deleted; > } > >+=head3 move_hold >+ >+$hold->move_hold(); >+ >+=cut >+ >+sub move_hold { >+ my ( $self, $args ) = @_; >+ >+ my $original = $self; >+ my $original_biblionumber = $self->biblionumber; >+ >+ my $patron = Koha::Patrons->find( { borrowernumber => $self->borrowernumber } ); >+ return { success => 0, error => 'Missing patron or target' } unless $patron; >+ >+ my ( $new_biblionumber, $new_itemnumber, $item, $canReserve ); >+ >+ if ( $args->{new_itemnumber} ) { >+ $item = Koha::Items->find( { itemnumber => $args->{new_itemnumber} } ) >+ or return { success => 0, error => 'Target item not found' }; >+ >+ $new_itemnumber = $item->itemnumber; >+ $new_biblionumber = $item->biblionumber; >+ >+ $canReserve = C4::Reserves::CanItemBeReserved( $patron, $item, $self->branchcode, { ignore_hold_counts => 1 } ); >+ } elsif ( $args->{new_biblionumber} ) { >+ $new_biblionumber = $args->{new_biblionumber}; >+ >+ $canReserve = C4::Reserves::CanBookBeReserved( >+ $patron->borrowernumber, $new_biblionumber, $self->branchcode, >+ { ignore_hold_counts => 1 } >+ ); >+ } else { >+ return { success => 0, error => 'Missing itemnumber or biblionumber' }; >+ } >+ >+ return { success => 0, error => $canReserve->{status} } >+ unless $canReserve->{status} eq 'OK'; >+ >+ my $max = Koha::Holds->search( >+ { biblionumber => $new_biblionumber }, >+ { order_by => { -desc => 'priority' }, rows => 1 } >+ )->next; >+ my $base_priority = $max ? $max->priority : 0; >+ my $priority = $base_priority + 1; >+ my $new_priority = C4::Reserves::_ShiftPriority( $new_biblionumber, $priority ); >+ >+ $self->update( >+ { >+ itemnumber => $new_itemnumber, # undef for biblio-level is fine >+ biblionumber => $new_biblionumber, >+ priority => $new_priority, >+ } >+ ); >+ >+ C4::Log::logaction( 'HOLDS', 'MODIFY', $self->reserve_id, $self, undef, $original ) >+ if C4::Context->preference('HoldsLog'); >+ >+ return { success => 1, hold => $self }; >+} >+ > =head3 set_transfer > > =cut >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 2d65e83dc1f..0d26304999e 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/holds_table.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/holds_table.inc >@@ -49,7 +49,15 @@ > [%- END -%] > [% SET tr_class = hold.suspend ? 'suspend' : '' %] > <tr class="[% tr_class | html %]"> >- <td><input type="checkbox" class="select_hold" data-id="[% hold.reserve_id | html %]" /></td> >+ <td >+ ><input >+ type="checkbox" >+ class="select_hold" >+ data-id="[% hold.reserve_id | html %]" >+ data-item_level_hold="[% hold.item_level_hold | html %]" >+ data-itemnumber="[% hold.itemnumber | html %]" >+ data-biblionumber="[% hold.biblionumber | html %]" >+ /></td> > <td> > <input type="hidden" name="reserve_id" value="[% hold.reserve_id | html %]" /> > <input type="hidden" name="borrowernumber" value="[% hold.borrowernumber | html %]" /> >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 558b5e0d9f0..790fe2dd15a 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt >@@ -105,6 +105,9 @@ > :disabled { > opacity: 0.5; > } >+ #toolbar { >+ align-items: center; >+ } > </style> > [% END %] > </head> >@@ -171,6 +174,60 @@ > </div> > [% END %] > >+ [% IF ( hold_move_successes ) %] >+ <div class="alert alert-success"> >+ <p>Moved the following holds:</p> >+ <ul> >+ [% FOREACH hold IN hold_move_successes %] >+ <li> >+ <label>Hold ID: </label> >+ <span>[% hold.hold_id | html %]</span> >+ <span> - Moved from [%- INCLUDE 'biblio-title.inc' biblio=hold.original_biblio link = 1 -%] to [%- INCLUDE 'biblio-title.inc' biblio=hold.target_biblio link = 1 -%]</span> >+ </li> >+ [% END %] >+ </ul> >+ </div> >+ [% END %] >+ [% IF ( hold_move_failures ) %] >+ <div class="alert alert-warning"> >+ <strong>One or more holds were not moved due to following errors:</strong> >+ <ul> >+ [% FOREACH fail IN hold_move_failures %] >+ <li> >+ <label>Hold ID: </label> >+ <span>[% fail.hold_id | html %]</span> >+ [% SWITCH fail.error %] >+ [% CASE 'cannotReserveFromOtherBranches' %] >+ <span>Target item cannot be reserved from other branches</span> >+ [% CASE 'ageRestricted' %] >+ <span>The target record and/or items are age restricted</span> >+ [% CASE 'alreadypossession' %] >+ <span>Target item is already checked out to patron</span> >+ [% CASE 'noReservesAllowed' %] >+ <span>No holds are allowed on the target item(s)</span> >+ [% CASE 'tooManyReservesToday' %] >+ <span>Target item has too many holds placed on it today</span> >+ [% CASE 'tooManyReserves' %] >+ <span>Target item has too many holds placed on it</span> >+ [% CASE 'notReservable' %] >+ <span>Target item is not reservable</span> >+ [% CASE 'cannotReserveFromOtherBranches' %] >+ <span>Target item cannot be placed on reserve for this branch</span> >+ [% CASE 'branchNotInHoldGroup' %] >+ <span>Tagret item is not in the local hold group</span> >+ [% CASE 'notforloan' %] >+ <span>Target item is not for loan</span> >+ [% CASE 'damaged' %] >+ <span>Target item is damaged</span> >+ [% CASE %] >+ <span>Error: [% fail.error | html %]</span> >+ [% END %] >+ </li> >+ [% END %] >+ </ul> >+ </div> >+ [% END %] >+ > [% IF ( failed_holds ) %] > <div class="alert alert-warning"> > <strong>One or more holds were not placed due to following errors:</strong> >@@ -1235,6 +1292,15 @@ > </select> > [% END %] > </fieldset> >+ [% IF ( CAN_user_reserveforothers_alter_hold_targets ) %] >+ <div class="btn-group"> >+ <a class="btn btn-default btn-xs dropdown-toggle move_selected_holds" id="item_record_choice" role="button" data-bs-toggle="dropdown" href="#" aria-expanded="false"></a> >+ <ul class="dropdown-menu" role="menu" aria-labelledby="item_record_choice" style=""> >+ <li><a class="dropdown-item move_hold_item" href="#">Item level holds to a different item</a></li> >+ <li><a class="dropdown-item move_hold_record" href="#">Record level holds to a different record</a></li> >+ </ul> >+ </div> >+ [% END %] > </div> > <div class="page-section"> > [% FOREACH biblioloo IN biblioloop %] >@@ -1416,6 +1482,104 @@ > </div> > </div> > </div> >+<div id="moveHoldItemModal" class="modal modal-lg" tabindex="-1" role="dialog" aria-hidden="true"> >+ <div class="modal-dialog"> >+ <div class="modal-content"> >+ <div class="modal-header"> >+ <h1 class="modal-title">Move hold(s) to a different item</h1> >+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> >+ </div> >+ <div class="modal-body"> >+ <div id="move_hold_item_selection"> >+ <h3>1. Review holds to move</h3> >+ <table class="table table-striped"> >+ <thead> >+ <tr> >+ <th>Hold ID</th> >+ <th>Original hold</th> >+ <th>Problem</th> >+ </tr> >+ </thead> >+ <tbody> </tbody> >+ </table> >+ </div> >+ <hr /> >+ <div id="move_hold_item_search" class="alert alert-danger" style="display:none;"></div> >+ <form id="itemSearchForm"> >+ <div id="move_hold_item_searchform"> >+ <h3>2. Enter the item barcode of new hold target: </h3> >+ <fieldset class="action"> >+ <input type="text" class="form-control" name="external_id" id="external_id" required /> >+ <button type="submit" class="btn btn-default mt-3">Search</button> >+ </fieldset> >+ </div> >+ </form> >+ <form id="move_hold_item_form" method="post" action="request.pl"> >+ <div id="itemResultMessage" class="mt-3"> </div> >+ <div id="move_hold_item_confirm" style="display:none;"> >+ <h3>3. Confirm moving of holds:</h3> >+ [% INCLUDE 'csrf-token.inc' %] >+ <input type="hidden" name="op" value="cud-move_hold_item" /> >+ <button type="submit" class="btn btn-primary mt-3">Move selected holds</button> >+ <input type="hidden" name="original_biblionumber" value="[% biblio.biblionumber %]" /> >+ </div> >+ </form> >+ </div> >+ <div class="modal-footer"> >+ <button type="button" class="btn btn-default" data-bs-dismiss="modal">Cancel</button> >+ </div> >+ </div> >+ </div> >+</div> >+<div id="moveHoldBiblioModal" class="modal modal-lg" tabindex="-1" role="dialog" aria-hidden="true"> >+ <div class="modal-dialog"> >+ <div class="modal-content"> >+ <div class="modal-header"> >+ <h1 class="modal-title">Move hold(s) to a different record</h1> >+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> >+ </div> >+ <div class="modal-body"> >+ <div id="move_hold_item_selection"> >+ <h3>1. Review holds to move</h3> >+ <table class="table table-striped"> >+ <thead> >+ <tr> >+ <th>Hold ID</th> >+ <th>Original hold</th> >+ <th>Problem</th> >+ </tr> >+ </thead> >+ <tbody> </tbody> >+ </table> >+ </div> >+ <hr /> >+ <div id="move_hold_biblio_search" class="alert alert-danger" style="display:none;"></div> >+ <form id="biblioSearchForm"> >+ <div id="move_hold_item_searchform"> >+ <h3>2. Enter the bibloinumber of the new hold target: </h3> >+ <fieldset class="action"> >+ <input type="text" class="form-control" name="biblio_id" id="biblio_id" required /> >+ <button type="submit" class="btn btn-default mt-3">Search</button> >+ </fieldset> >+ </div> >+ </form> >+ <form id="move_hold_biblio_form" method="post" action="request.pl"> >+ <div id="biblioResultMessage" class="mt-3"> </div> >+ <div id="move_hold_biblio_confirm" style="display:none;"> >+ <h3>3. Confirm moving of holds:</h3> >+ [% INCLUDE 'csrf-token.inc' %] >+ <input type="hidden" name="op" value="cud-move_hold_biblio" /> >+ <button type="submit" class="btn btn-primary mt-3">Move selected holds</button> >+ <input type="hidden" name="original_biblionumber" value="[% biblio.biblionumber %]" /> >+ </div> >+ </form> >+ </div> >+ <div class="modal-footer"> >+ <button type="button" class="btn btn-default" data-bs-dismiss="modal">Cancel</button> >+ </div> >+ </div> >+ </div> >+</div> > <div id="hold-actions"> > <form id="hold-actions-form"> [% INCLUDE 'csrf-token.inc' %] </form> > </div> >@@ -1467,6 +1631,7 @@ > } > > var MSG_CANCEL_SELECTED = _("Cancel selected (%s)"); >+ var MSG_MOVE_SELECTED = _("Move selected (%s)"); > var MSG_CANCEL_ALERT = _("This action will cancel <span class='badge'>%s</span> hold(s)."); > $.fn.select2.defaults.set("width", "100%" ); > $.fn.select2.defaults.set("dropdownAutoWidth", true ); >@@ -1731,6 +1896,91 @@ > } > > $(document).ready(function() { >+ $("#itemSearchForm").on("submit", function (event) { >+ event.preventDefault(); >+ >+ let externalID = $("#external_id").val(); >+ let apiUrl = `/api/v1/items?external_id=${encodeURIComponent(externalID)}`; >+ >+ $.ajax({ >+ url: apiUrl, >+ method: "GET", >+ dataType: "json", >+ success: function (data) { >+ if (data.length > 0) { >+ let resultHtml = ""; >+ $.each(data, function (index, item) { >+ resultHtml += ` >+ <div class="alert alert-success"> >+ <strong>Biblionumber:</strong> ${item.biblio_id} <br> >+ <strong>Item:</strong> ${item.external_id} <br> >+ <input id="new_itemnumber_${item.item_id}" name="new_itemnumber" type="checkbox" value="${item.item_id}"> >+ <label for="new_itemnumber_${item.item_id}">Move all selected item level holds to this item</label> >+ <input id="new_biblionumber_${item.item_id}" name="new_biblionumber" type="hidden" value="${item.biblio_id}"> >+ </div> >+ <hr /> >+ `; >+ }); >+ $("#itemResultMessage").html(resultHtml); >+ } else { >+ $("#itemResultMessage").html(` >+ <div class="alert alert-warning">No item found with barcode: ${externalID}.</div> >+ `); >+ } >+ }, >+ }); >+ }); >+ >+ $("#biblioSearchForm").on("submit", function (event) { >+ event.preventDefault(); >+ >+ let biblioID = $("#biblio_id").val(); >+ let apiUrl = `/api/v1/items?q={"biblio_id":"${encodeURIComponent(biblioID)}"}`; >+ >+ $.ajax({ >+ url: apiUrl, >+ method: "GET", >+ dataType: "json", >+ success: function (data) { >+ if (data.length > 0) { >+ let resultHtml = ""; >+ $.each(data, function (index, item) { >+ resultHtml += ` >+ <div class="alert alert-success"> >+ <strong>Biblionumber:</strong> ${item.biblio_id} <br> >+ <input id="new_biblionumber_${item.biblio_id}" name="new_biblionumber" type="checkbox" value="${item.biblio_id}"> >+ <label for="new_biblionumber_${item.biblio_id}">Move all selected record level holds to this record</label> >+ </div> >+ <hr /> >+ `; >+ }); >+ $("#biblioResultMessage").html(resultHtml); >+ } else { >+ $("#biblioResultMessage").html(` >+ <div class="alert alert-warning">No item found with barcode: ${biblioID}.</div> >+ `); >+ } >+ }, >+ }); >+ }); >+ >+ $(document).on("change", 'input[name="new_itemnumber"]', function() { >+ $('input[name="new_itemnumber"]').not(this).prop("checked", false); >+ if ( $('input[name="new_itemnumber"]:checked').length ){ >+ $('#move_hold_item_confirm').show(); >+ } else { >+ $('#move_hold_item_confirm').hide(); >+ } >+ }); >+ >+ $(document).on("change", 'input[name="new_biblionumber"]', function() { >+ $('input[name="new_biblionumber"]').not(this).prop("checked", false); >+ if ( $('input[name="new_biblionumber"]:checked').length ){ >+ $('#move_hold_biblio_confirm').show(); >+ } else { >+ $('#move_hold_biblio_confirm').hide(); >+ } >+ }); > > $("#always_show_holds").change(function(){ > if( $(this).prop('checked') ){ >@@ -1834,6 +2084,7 @@ > }); > > $('.cancel_selected_holds').html(MSG_CANCEL_SELECTED.format($('.holds_table .select_hold:checked').length)); >+ $('.move_selected_holds').html(MSG_MOVE_SELECTED.format($('.holds_table .select_hold:checked').length)); > > $('.holds_table .select_hold_all').click(function() { > var table = $(this).parents('.holds_table'); >@@ -1841,6 +2092,7 @@ > $('.select_hold', table).prop('checked', !count); > $(this).prop('checked', !count); > $('.cancel_selected_holds').html(MSG_CANCEL_SELECTED.format($('.holds_table .select_hold:checked').length)); >+ $('.move_selected_holds').html(MSG_MOVE_SELECTED.format($('.holds_table .select_hold:checked').length)); > $('#cancel_hold_alert').html( MSG_CANCEL_ALERT.format($('.holds_table .select_hold:checked').length)); > $('#cancel_hold_alert').show(); > localStorage.selectedHolds = $('.holds_table .select_hold:checked').toArray().map(el => $(el).data('id')); >@@ -1851,11 +2103,54 @@ > var count = $('.select_hold:not(:checked)', table).length; > $('.select_hold_all', table).prop('checked', !count); > $('.cancel_selected_holds').html(MSG_CANCEL_SELECTED.format($('.holds_table .select_hold:checked').length)); >+ $('.move_selected_holds').html(MSG_MOVE_SELECTED.format($('.holds_table .select_hold:checked').length)); > $('#cancel_hold_alert').html( MSG_CANCEL_ALERT.format($('.holds_table .select_hold:checked').length)); > $('#cancel_hold_alert').show(); > localStorage.selectedHolds = $('.holds_table .select_hold:checked').toArray().map(el => $(el).data('id')); > }); > >+ $('.move_hold_item').click(function(e) { >+ e.preventDefault(); >+ if($('.holds_table .select_hold:checked').length) { >+ $('#itemResultMessage').empty(); >+ $('#move_hold_item_selection table tbody').empty(); >+ $('#moveHoldItemModal').modal('show'); >+ $('.select_hold:checked').each( function() { >+ let reserve_id = $(this).data('id'); >+ let reserve_biblionumber = $(this).data('biblionumber'); >+ let reserve_itemnumber = $(this).data('itemnumber'); >+ let item_level_hold = $(this).data('item_level_hold'); >+ let error_message = $(this).data('item_level_hold') ? "" : _("Cannot move a waiting or record level hold"); >+ let found_status = $(this).data('found'); >+ $('#move_hold_item_selection table').append(`<tr><td>${reserve_id}</td><td>Biblionumber: <a target="_blank" href="/cgi-bin/koha/reserve/request.pl?biblionumber=${reserve_biblionumber}">${reserve_biblionumber}</a> Itemnumber: <a target="_blank" href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=${reserve_biblionumber}#item${reserve_itemnumber}">${reserve_itemnumber}</a></td><td>${error_message}</td></tr>`) >+ if ( item_level_hold ) { >+ $('#move_hold_item_form').append(`<input type="hidden" name="hold_id" value="${reserve_id}">`); >+ } >+ }); >+ } >+ }); >+ >+ $('.move_hold_record').click(function(e) { >+ e.preventDefault(); >+ if($('.holds_table .select_hold:checked').length) { >+ $('#biblioResultMessage').empty(); >+ $('#move_hold_item_selection table tbody').empty(); >+ $('#moveHoldBiblioModal').modal('show'); >+ $('.select_hold:checked').each( function() { >+ let reserve_id = $(this).data('id'); >+ let reserve_biblionumber = $(this).data('biblionumber'); >+ let reserve_itemnumber = $(this).data('itemnumber'); >+ let item_level_hold = $(this).data('item_level_hold'); >+ let error_message = $(this).data('item_level_hold') ? _("Cannot move a waiting or item level hold") : ""; >+ let found_status = $(this).data('found'); >+ $('#move_hold_item_selection table').append(`<tr><td>${reserve_id}</td><td>Biblionumber: <a target="_blank" href="/cgi-bin/koha/reserve/request.pl?biblionumber=${reserve_biblionumber}">${reserve_biblionumber}</a></td><td>${error_message}</td></tr>`) >+ if ( !item_level_hold ) { >+ $('#move_hold_biblio_form').append(`<input type="hidden" name="hold_id" value="${reserve_id}">`); >+ } >+ }); >+ } >+ }); >+ > $('.cancel_selected_holds').click(function(e) { > e.preventDefault(); > if($('.holds_table .select_hold:checked').length) { >diff --git a/reserve/request.pl b/reserve/request.pl >index c5e354aa7d2..89c28d1e1dd 100755 >--- a/reserve/request.pl >+++ b/reserve/request.pl >@@ -44,6 +44,7 @@ use C4::Search qw( enabled_staff_search_views ); > use Koha::Biblios; > use Koha::Checkouts; > use Koha::Holds; >+use Koha::Hold; > use Koha::CirculationRules; > use Koha::Items; > use Koha::ItemTypes; >@@ -90,6 +91,7 @@ my $exceeded_maxreserves; > my $exceeded_holds_per_record; > my @failed_holds = $input->multi_param('failed_holds'); > my $form_submitted = $input->param('form_submitted'); >+my @biblionumbers = $input->multi_param('biblionumber'); > > my $op = $input->param('op') || q{}; > >@@ -109,6 +111,60 @@ if ( $op eq 'cud-move' ) { > $next_priority, $first_priority, $last_priority > ); > } >+} elsif ( $op eq 'cud-move_hold_item' or $op eq 'cud-move_hold_biblio' ) { >+ my @hold_ids = $input->multi_param('hold_id'); >+ my $original_biblionumber = $input->param('original_biblionumber'); >+ my @moving_holds = Koha::Holds->search( >+ { reserve_id => \@hold_ids }, >+ { order_by => { -asc => 'priority' } } >+ )->as_list; >+ >+ my $new_biblionumber = $input->param('new_biblionumber'); >+ my $target_biblio = Koha::Biblios->find($new_biblionumber); >+ >+ my %args = ( >+ new_biblionumber => $new_biblionumber, >+ ); >+ >+ # Only pass new_itemnumber if this is an item level move >+ if ( $op eq 'cud-move_hold_item' ) { >+ $args{new_itemnumber} = $input->param('new_itemnumber'); >+ } >+ >+ my @success_messages; >+ my @error_messages; >+ >+ foreach my $hold (@moving_holds) { >+ my $original_biblio = Koha::Biblios->find( $hold->biblionumber ); >+ >+ my $result = $hold->move_hold( \%args ); >+ >+ if ( $result->{success} ) { >+ push @success_messages, { >+ hold_id => $hold->id, >+ success => 1, >+ original_biblio => $original_biblio, >+ target_biblio => $target_biblio, >+ }; >+ } else { >+ push @error_messages, { >+ hold_id => $hold->id, >+ success => 0, >+ original_biblio => $original_biblio, >+ target_biblio => $target_biblio, >+ error => $result->{error}, >+ }; >+ } >+ } >+ >+ #Fix the priority on the original record >+ C4::Reserves::_FixPriority( { biblionumber => $original_biblionumber } ); >+ >+ $template->param( >+ hold_move_successes => \@success_messages, >+ hold_move_failures => \@error_messages, >+ ); >+ > } elsif ( $op eq 'cud-cancel' ) { > my $reserve_id = $input->param('reserve_id'); > my $cancellation_reason = $input->param("cancellation-reason"); >@@ -172,8 +228,6 @@ if ($form_submitted) { > } > } > >-my @biblionumbers = $input->multi_param('biblionumber'); >- > my $multi_hold = @biblionumbers > 1; > $template->param( > multi_hold => $multi_hold, >-- >2.39.5
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 31698
:
179226
|
179235
|
179236
|
179279
|
179287
|
179290
|
179291
|
179292
|
179295
|
179704
|
179711
|
179713
|
181222
|
181223
|
181224
|
181225
|
181226
|
181228
|
181229
|
181230
|
181231
|
181232
|
181233
|
181234
|
181929
|
181930
|
181944
|
181945
|
181946
|
181947
|
181948
|
181951
|
181952
|
181953
|
181954
|
181955
|
181956
|
181957
|
181958
|
181959
|
181960
|
181961
|
181962
|
182639
|
182640
|
182641