Bug 23269: use REST API for patron_holds_table

This patch uses the REST API to populate the holds table

Test plan:
1) Apply the patch
2) Go to a record with holds
3) Check that the holds table is populated correctly
4) Check that hold tables functions work correctly
5) Change HoldsSplitQueue and HoldsSplitQueueNumbering system preference, try all variations
6) Repeat steps 3 and 4
7) Search for records and place holds to multiple records
8) Repeat steps 3 and 4
9) Try with lesser permissions

Sponsored-by: Koha-Suomi Oy
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
This commit is contained in:
Johanna Räisä 2024-10-24 09:31:39 +03:00 committed by Martin Renvoize
parent 8b626ac95c
commit b58f945270
No known key found for this signature in database
GPG Key ID: 2D86E0EAEC83711B
10 changed files with 1425 additions and 760 deletions

View File

@ -783,6 +783,24 @@ sub is_suspended {
return $self->suspend();
}
=head3 item_level_holds
Returns the number (count) of item-level holds for this hold's biblionumber and patron
=cut
sub item_level_holds {
my ($self) = @_;
return Koha::Holds->search(
{
biblionumber => $self->biblionumber,
borrowernumber => $self->borrowernumber,
itemnumber => { '!=', undef },
}
)->count;
}
=head3 add_cancellation_request
my $cancellation_request = $hold->add_cancellation_request({ [ creation_date => $creation_date ] });

View File

@ -281,21 +281,27 @@ sub edit {
}
$pickup_library_id //= $hold->branchcode;
my $priority = $body->{priority} // $hold->priority;
my $hold_date = $body->{hold_date} // $hold->reservedate;
my $expiration_date = $body->{expiration_date} // $hold->expirationdate;
my $priority = $body->{priority} // $hold->priority;
my $hold_date = exists $body->{hold_date} ? $body->{hold_date} : $hold->reservedate;
my $expiration_date = exists $body->{expiration_date} ? $body->{expiration_date} : $hold->expirationdate;
my $item_id = exists $body->{item_id} ? $body->{item_id} : $hold->itemnumber;
my $item_level =
exists $body->{item_level}
? ( $body->{item_level} ? 1 : 0 )
: $hold->item_level_hold;
# suspended_until can also be set to undef
my $suspended_until = $body->{suspended_until} || $hold->suspend_until;
my $params = {
reserve_id => $hold->id,
branchcode => $pickup_library_id,
rank => $priority,
suspend_until => $suspended_until,
itemnumber => $hold->itemnumber,
reservedate => $hold_date,
expirationdate => $expiration_date,
reserve_id => $hold->id,
branchcode => $pickup_library_id,
rank => $priority,
suspend_until => $suspended_until,
itemnumber => $item_id,
reservedate => $hold_date,
expirationdate => $expiration_date,
item_level_hold => $item_level
};
C4::Reserves::ModReserve($params);

View File

@ -2141,6 +2141,7 @@ modules:
columnname: action
patron_holds_table:
default_sort_order: 1
columns:
-
columnname: checkbox

View File

@ -114,6 +114,11 @@ properties:
item_level:
type: boolean
description: If the hold is placed at item level
item_level_holds:
type:
- integer
- "null"
description: Count of item level holds for this bibliographic record
cancellation_requested:
type:
- boolean
@ -134,6 +139,11 @@ properties:
- object
- "null"
description: The item
item_group:
type:
- object
- "null"
description: The item group
pickup_library:
type:
- object

View File

@ -108,6 +108,8 @@
- pickup_library
- item
- patron
- item_group
- item_level_holds
collectionFormat: csv
produces:
- application/json
@ -430,12 +432,26 @@
format: date-time
hold_date:
description: Hold date
type: string
type:
- string
- "null"
format: date
expiration_date:
description: Hold's expiration date
type: string
type:
- string
- "null"
format: date
item_id:
description: Internal item identifier
type:
- integer
- "null"
item_level:
description: Whether the hold is item-level or not
type:
- boolean
- "null"
additionalProperties: false
consumes:
- application/json

View File

@ -2,379 +2,25 @@
[% SET hold_cancellation = AuthorisedValues.GetAuthValueDropbox('HOLD_CANCELLATION') %]
[% USE AuthorisedValues %]
<table id="patron_holds_table" class="holds_table">
[%#This include depends on the asset js/form-submit.js. Any template making use of this include must import form-submit.js as well. %]
[%#FIXME can form-submit.js be imported into this file directly? %]
<table id="patron_holds_table_[% biblio_id | html %]_[% split_data | html %]" class="holds_table" data-total-holds="[% total_holds | html %]">
<thead>
<tr>
<th id="checkbox" data-colname="checkbox"><input type="checkbox" class="select_hold_all" /></th>
<th id="priority" data-colname="priority">Priority</th>
[% IF ( CAN_user_reserveforothers_modify_holds_priority ) %]
<th id="change_priority" data-colname="change_priority">Change priority</th>
[% END %]
<th id="change_priority" data-colname="change_priority">Change priority</th>
<th id="patron" data-colname="patron">Patron</th>
<th id="notes" data-colname="notes">Notes</th>
<th id="date" data-colname="date">Date</th>
<th id="expiration" data-colname="expiration">Expiration</th>
<th id="pickup_library" data-colname="pickup_library">Pickup library</th>
<th id="details" data-colname="details">Details</th>
[% IF ( CAN_user_reserveforothers_modify_holds_priority ) %]
<th id="set_lowest_priority" data-colname="set_lowest_priority"><span style="display:none;">Set lowest priority</span><i class="fa fa-lg fa-rotate-90 fa-fast-forward" title="Toggle set to lowest priority"></i></th>
[% END %]
<th id="set_lowest_priority" data-colname="set_lowest_priority"><span style="display:none;">Set lowest priority</span><i class="fa fa-lg fa-rotate-90 fa-fast-forward" title="Toggle set to lowest priority"></i></th>
<th id="delete" data-colname="delete">Delete</th>
<th id="suspend" data-colname="suspend">Suspend</th>
<th id="print_slip" data-colname="print_slip">Print hold/transfer slip</th>
</tr>
</thead>
[%- SET first_priority = 0 -%]
[%- SET found_holds = 0 -%]
[%- SET last_priority = holds.last.priority -%]
[% SET all_priorities = [] %]
[% FOREACH hold IN holds %]
[% all_priorities.push( hold.priority ) %]
[% END %]
<tbody>
[% FOREACH hold IN holds %]
[%- IF !hold.found && first_priority == 0 -%]
[%- first_priority = hold.priority -%]
[%- found_holds = loop.index() -%]
[%- END -%]
[%- IF Koha.Preference('HoldsSplitQueueNumbering') == 'actual' -%]
[%- this_priority = hold.priority -%]
[%- ELSE -%]
[%- this_priority = loop.count() - found_holds -%]
[%- 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 %]"
data-item_level_hold="[% hold.item_level_hold | html %]"
data-itemnumber="[% hold.itemnumber | html %]"
data-biblionumber="[% hold.biblionumber | html %]"
data-waiting="[% hold.atdestination | html %]"
data-intransit="[% hold.intransit | html %]"
/></td>
<td style="min-width:185px;" data-order="[% priority | html %]">
<div>
<input type="hidden" name="reserve_id" value="[% hold.reserve_id | html %]" />
<input type="hidden" name="borrowernumber" value="[% hold.borrowernumber | html %]" />
<input type="hidden" name="biblionumber" value="[% hold.biblionumber | html %]" />
[% IF ( CAN_user_reserveforothers_modify_holds_priority ) %]
[% IF Koha.Preference('HoldsSplitQueue') == "nothing" && !hold.found %]
<label for="rank-request_[% hold.reserve_id | html %]">Change priority to:</label>
<select name="rank-request" id="rank-request_[% hold.reserve_id | html %]" class="rank-request" data-hold-id="[% hold.reserve_id | html %]">
[% IF ( CAN_user_reserveforothers_modify_holds_priority ) %]
[% FOREACH priority IN all_priorities %]
[% IF priority == this_priority %]
<option value="[% priority | html %]" selected="selected">[% priority | html %]</option>
[% ELSIF priority > 0 %]
<option value="[% priority | html %]">[% priority | html %]</option>
[% END %]
[% END %]
[% ELSE %]
<option value="[% hold.priority | html %]" selected="selected">[% this_priority | html %]</option>
[% END %]
<option value="del">del</option>
</select>
[% ELSE %]
<input type="hidden" name="rank-request" class="rank-request" value="[% hold.priority | html %]" data-hold-id="[% hold.reserve_id | html %]" />
<select name="rank-request" class="rank-request" disabled="disabled" data-hold-id="[% hold.reserve_id | html %]">
[% IF ( hold.found ) %]
[% IF ( hold.intransit ) %]
<option value="T" selected="selected">In transit</option>
[% ELSIF (hold.inprocessing) %]
<option value="P" selected="selected">In processing</option>
[% ELSE %]
<option value="W" selected="selected">Waiting</option>
[% END %]
[% ELSE %]
<option value="[% hold.priority | html %]" selected="selected">[% this_priority | html %]</option>
[% END %]
</select>
[% END %]
[% ELSE %]
<input type="hidden" name="rank-request" class="rank-request" value="[% hold.priority | html %]" data-hold-id="[% hold.reserve_id | html %]" />
[% END %]
<div>
<label for="current_priority_[% hold.reserve_id | html %]">Current priority: </label>
<span id="current_priority_[% hold.reserve_id | html %]" class="current_priority badge text-bg-info">[% hold.priority | html %]</span>
</div>
</div>
</td>
[%- IF ( CAN_user_reserveforothers_modify_holds_priority ) -%]
[%- UNLESS hold.found -%]
[%- SET prev_priority = loop.prev.priority -%]
[%- SET next_priority = loop.next.priority -%]
<td style="white-space:nowrap;">
<a
class="hold-arrow"
title="Move hold up"
data-op="cud-move"
data-where="up"
data-first_priority="[% first_priority | html %]"
data-last_priority="[% last_priority | html %]"
data-prev_priority="[% prev_priority | html %]"
data-next_priority="[% next_priority | html %]"
data-borrowernumber="[% hold.borrowernumber | html %]"
data-biblionumber="[% hold.biblionumber | html %]"
data-reserve_id="[% hold.reserve_id | html %]"
data-date="[% hold.date | html %]"
>
<i class="fa fa-lg icon-move-hold-up" aria-hidden="true"></i>
</a>
<a
class="hold-arrow"
title="Move hold to top"
data-op="cud-move"
data-where="top"
data-first_priority="[% first_priority | html %]"
data-last_priority="[% last_priority | html %]"
data-prev_priority="[% prev_priority | html %]"
data-next_priority="[% next_priority | html %]"
data-borrowernumber="[% hold.borrowernumber | html %]"
data-biblionumber="[% hold.biblionumber | html %]"
data-reserve_id="[% hold.reserve_id | html %]"
data-date="[% hold.date | html %]"
>
<i class="fa fa-lg icon-move-hold-top" aria-hidden="true"></i>
</a>
<a
class="hold-arrow"
title="Move hold to bottom"
data-op="cud-move"
data-where="bottom"
data-first_priority="[% first_priority | html %]"
data-last_priority="[% last_priority | html %]"
data-prev_priority="[% prev_priority | html %]"
data-next_priority="[% next_priority | html %]"
data-borrowernumber="[% hold.borrowernumber | html %]"
data-biblionumber="[% hold.biblionumber | html %]"
data-reserve_id="[% hold.reserve_id | html %]"
data-date="[% hold.date | html %]"
>
<i class="fa fa-lg icon-move-hold-bottom" aria-hidden="true"></i>
</a>
<a
class="hold-arrow"
title="Move hold down"
data-op="cud-move"
data-where="down"
data-first_priority="[% first_priority | html %]"
data-last_priority="[% last_priority | html %]"
data-prev_priority="[% prev_priority | html %]"
data-next_priority="[% next_priority | html %]"
data-borrowernumber="[% hold.borrowernumber | html %]"
data-biblionumber="[% hold.biblionumber | html %]"
data-reserve_id="[% hold.reserve_id | html %]"
data-date="[% hold.date | html %]"
>
<i class="fa fa-lg icon-move-hold-down" aria-hidden="true"></i>
</a>
</td>
[%- ELSE -%]
<td></td>
[%- END -%]
[%- END -%]
<td> [% INCLUDE 'patron-title.inc' patron=hold.patron hide_patron_infos_if_needed=1 %] </td>
<td>[% hold.notes | html | html_line_break %]</td>
<td data-order="[% hold.date| html %]">
[% IF Koha.Preference('AllowHoldDateInFuture') %]
<input type="text" class="flatpickr" value="[% hold.date | html %]" required="required" size="10" name="reservedate" />
[% ELSE %]
[% hold.date | $KohaDates %]
[% END %]
</td>
<td>
<input type="text" class="flatpickr" data-flatpickr-futuredate="true" value="[% hold.expirationdate | html %]" size="10" name="expirationdate" />
</td>
<td>
[%- IF ( hold.found ) -%]
<input type="hidden" name="pickup" value="[% hold.wbrcode | html %]" />
[%- IF ( hold.atdestination ) -%]
Item waiting at <strong> [% hold.wbrname | html %]</strong>[% IF hold.desk_name %], [% hold.desk_name | html %],[% END %] since [% hold.waiting_date | $KohaDates %]
[%- ELSIF (hold.intransit) -%]
Item being transferred to <strong> [% hold.wbrname | html %]</strong>
[%- ELSIF (hold.inprocessing) -%]
Item being processed at <strong> [% hold.wbrname | html %]</strong>
[%- ELSE -%]
Hold expected at <strong>[% hold.wbrname | html %]</strong>, please checkin to verify status
[%- END -%]
[%- ELSE -%]
[%- IF Koha.Preference('IndependentBranches') && Branches.all().size == 1 -%]
[% Branches.GetName(hold.branchcode) | html %] <input type="hidden" name="pickup" value="[% hold.branchcode | html %]" />
[%- ELSE -%]
<select class="pickup_location_dropdown" data-selected="[% hold.branchcode | html %]" data-hold-id="[% hold.reserve_id | html %]" data-pickup-location-source="hold" name="pickup">
<option selected="selected" value="[% hold.branchcode | html %]">[% Branches.GetName(hold.branchcode) | html %]</option>
<option value="" disabled="disabled" class="loading">Loading...</option>
</select>
<img class="loading_[% hold.reserve_id | html %]" src="[% interface | html %]/[% theme | html %]/img/spinner-small.gif" alt="" style="display:none;" />
[%- END -%]
[%- END -%]
</td>
<td>
[%- IF ( hold.found ) -%]
<a href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=[% hold.biblionumber | uri %]&amp;itemnumber=[% hold.itemnumber | uri %]#item[% hold.itemnumber | uri %]">
[%- IF ( hold.barcodenumber ) -%]
[%- hold.barcodenumber | html -%]
[%- ELSE -%]
<span>No barcode</span>
[%- END -%]
<input type="hidden" name="itemnumber" value="[% hold.itemnumber | html %]" />
</a>
[%- ELSE -%]
[%- IF ( hold.item_level_hold ) -%]
<em>
[%- IF ! hold.change_hold_type_allowed -%]
<span>Only item</span>
<a href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=[% hold.biblionumber | uri %]&amp;itemnumber=[% hold.itemnumber | uri %]#item[% hold.itemnumber | uri %]">
[%- IF ( hold.barcodenumber ) -%]
[%- hold.barcodenumber | html -%]
[%- ELSE -%]
<span>No barcode</span>
[%- END -%]
<input type="hidden" name="itemnumber" value="[% hold.itemnumber | html %]" />
</a>
[%- ELSE -%]
<select name="change_hold_type_[% hold.reserve_id | html %]">
<option selected="selected" value="">
[%- IF ( hold.barcodenumber ) -%]
[% tx("Only item {barcode}", {barcode = hold.barcodenumber}) | html %]
[%- ELSE -%]
[% t("Only item [No barcode]") | html %]
[%- END -%]
</option>
<option value="1">Next available</option>
</select>
[%- IF ( hold.itemnumber ) -%]
<input type="hidden" name="itemnumber" value="[% hold.itemnumber | html %]" />
[%- END -%]
[%- IF hold.itemtype -%]
<span style="display:none">Next available [% ItemTypes.GetDescription( hold.itemtype ) | html %] item</span>
[%- ELSE -%]
<span style="display:none">Next available</span>
[%- END -%]
[%- END -%]
</em>
[%- ELSE -%]
[%- IF hold.itemtype -%]
<em>Next available [% ItemTypes.GetDescription( hold.itemtype ) | html %] item</em>
[%- ELSIF hold.object.item_group -%]
<em>Next available item from group <strong>[% hold.object.item_group.description | html %]</strong></em>
[%- ELSE -%]
<em>Next available</em>
[%- END -%]
<input type="hidden" name="itemnumber" value="" />
[%- END -%]
[%- END -%]
[%- IF hold.non_priority -%]
<br /><i>Non priority hold</i>
[%- END -%]
[%- IF hold.hold_group_id -%]
<div>(part of a <a href="/cgi-bin/koha/reserve/hold-group.pl?hold_group_id=[% hold.hold_group_id | uri %]" class="hold-group">hold group</a>)</div>
[%- END -%]
</td>
[%- IF ( CAN_user_reserveforothers_modify_holds_priority ) -%]
[%- UNLESS hold.found -%]
<td>
[% IF ( hold.lowestPriority ) %]
<a
class="hold-arrow"
title="Remove lowest priority"
data-op="cud-setLowestPriority"
data-borrowernumber="[% hold.borrowernumber | html %]"
data-biblionumber="[% hold.biblionumber | html %]"
data-reserve_id="[% hold.reserve_id | html %]"
data-date="[% hold.date | html %]"
>
<i class="fa fa-lg fa-rotate-90 icon-unset-lowest" aria-hidden="true"></i>
</a>
[% ELSE %]
<a
class="hold-arrow"
title="Set lowest priority"
data-op="cud-setLowestPriority"
data-borrowernumber="[% hold.borrowernumber | html %]"
data-biblionumber="[% hold.biblionumber | html %]"
data-reserve_id="[% hold.reserve_id | html %]"
data-date="[% hold.date | html %]"
>
<i class="fa fa-lg fa-rotate-90 icon-set-lowest" aria-hidden="true"></i>
</a>
[% END %]
</td>
[%- ELSE -%]
<td></td>
[%- END -%]
[%- END -%]
<td>
<a class="cancel-hold deny" title="Cancel hold" data-borrowernumber="[% hold.borrowernumber | html %]" data-biblionumber="[% hold.biblionumber | html %]" data-id="[% hold.reserve_id | html %]" href="#">
<i class="fa fa-trash" aria-label="Cancel hold"></i>
</a>
</td>
<td>
[% IF Koha.Preference('SuspendHoldsIntranet') %]
[% UNLESS ( hold.found ) %]
[% IF ( hold.suspend ) %]
<button class="btn btn-default btn-xs unsuspend-hold" data-reserve-id="[% hold.reserve_id | html %]" data-biblionumber="[% hold.biblionumber | html %]">
<i class="fa fa-play" aria-hidden="true"></i> Unsuspend
</button>
[% ELSE %]
<button class="btn btn-default btn-xs suspend-hold" data-reserve-id="[% hold.reserve_id | html %]" data-biblionumber="[% hold.biblionumber | html %]">
<i class="fa fa-pause" aria-hidden="true"></i> Suspend
</button>
[% END %]
[% IF Koha.Preference('AutoResumeSuspendedHolds') %]
<label for="suspend_until_[% hold.reserve_id | html %]">[% IF ( hold.suspend ) %]on[% ELSE %]until[% END %]</label>
<input
type="text"
name="suspend_until_[% hold.reserve_id | html %]"
id="suspend_until_[% hold.reserve_id | html %]"
size="10"
value="[% hold.suspend_until | html %]"
class="flatpickr"
data-flatpickr-futuredate="true"
/>
[%- ELSE -%]
<input type="hidden" name="suspend_until_[% hold.reserve_id | html %]" id="suspend_until_[% hold.reserve_id | html %]" value="" />
[%- END -%]
[%- END -%]
[%- END # IF SuspendHoldsIntranet -%]
[%- IF ( hold.found ) -%]
<a
class="btn btn-default submit-form-link"
href="#"
id="revert_hold_[% hold.reserve_id | html %]"
data-op="cud-move"
data-where="down"
data-first_priority="[% first_priority | html %]"
data-last_priority="[% last_priority | html %]"
data-prev_priority="0"
data-next_priority="1"
data-borrowernumber="[% hold.borrowernumber | html %]"
data-biblionumber="[% hold.biblionumber | html %]"
data-itemnumber="[% hold.itemnumber | html %]"
data-reserve_id="[% hold.reserve_id | html %]"
data-date="[% hold.date | html %]"
data-action="request.pl"
data-method="post"
>[% IF hold.intransit %]Revert transit status[% ELSE %]Revert waiting status[% END %]</a
>
[%- END -%]
</td>
[% IF ( hold.intransit || hold.atdestination ) %]
<td><input class="printholdslip" type="button" name="printholdslip" value="Print slip" data-reserve_id="[% hold.reserve_id | html %]" /></td>
[% ELSE %]
<td></td>
[% END %]
</tr>
[% END %]
</tbody>
</table>

View File

@ -1311,7 +1311,7 @@
[% END %]
[% END %]
[% END %]
[% IF ( reserveloop ) %]
[% IF ( total_holds ) %]
<form id="existing_holds" name="T[% time | html %]" action="modrequest.pl" method="post" style="display:block">
[% INCLUDE 'csrf-token.inc' %]
[% IF ( multi_hold ) %]
@ -1330,11 +1330,7 @@
<h2>Existing holds</h2>
<div id="toolbar" class="btn-toolbar sticky">
<div class="btn-group">
<input type="hidden" name="op" value="cud-modifyall" />
<input type="submit" class="btn btn-primary" name="submit" value="Update hold(s)" />
</div>
<div class="btn-group">
<button class="btn cancel_selected_holds" data-bulk="true"> Cancel selected (<span class="selected_holds_count"></span>)</button>
<button class="btn cancel_selected_holds" data-bulk="true"></button>
</div>
<div id="cancellation-reason-div" style="display:none">
[% SET hold_cancellation = AuthorisedValues.GetAuthValueDropbox('HOLD_CANCELLATION') %]
@ -1360,137 +1356,75 @@
</div>
<div class="page-section">
[% FOREACH biblioloo IN biblioloop %]
[% IF ( biblioloo.reserveloop ) %]
[% IF ( biblioloo.total_holds ) %]
<div class="hold_title" id="hold_title_[% biblioloo.biblionumber | html %]">
[% IF ( multi_hold ) %]
<h3>
<a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% biblioloo.biblionumber | uri %]"> [% biblioloo.title | html %] </a>
<span class="badge bg-info-subtle"><span>[% biblioloo.reserveloop.size | html %] [% tn('Hold', 'Holds', biblioloo.reserveloop.size) | $raw %]</span></span>
<span class="badge bg-info-subtle"><span>[% biblioloo.total_holds | html %] [% tn('Hold', 'Holds', biblioloo.total_holds) | $raw %]</span></span>
</h3>
[% END %]
[% IF Koha.Preference('HoldsSplitQueue') == 'branch' %]
[% SET branchcodes = [] %]
[% FOREACH h IN biblioloo.reserveloop %]
[% branchcodes.push( h.branchcode ) %]
[% END %]
[% branchcodes = branchcodes.unique %]
[% IF ( branchcodes.empty ) %]
<div class="alert alert-info"> There are no holds on this title. </div>
[% IF biblioloo.hold_branches.empty %]
<div class="holds_by_library">
<h4>Any library</h4>
[% INCLUDE holds_table.inc biblio_id=biblioloo.biblionumber total_holds=biblioloo.total_holds split_data="any" %]
</div>
[% ELSE %]
[% FOREACH b IN branchcodes.sort %]
[% SET holds_by_branch = [] %]
[% FOREACH h IN biblioloo.reserveloop %]
[% IF h.branchcode == b %]
[% holds_by_branch.push( h ) %]
[% END %]
[% END %]
[% FOREACH b IN biblioloo.hold_branches %]
<div class="holds_by_library">
<h4>[% Branches.GetName( b ) | html %]</h4>
[% INCLUDE holds_table.inc holds=holds_by_branch %]
[% INCLUDE holds_table.inc biblio_id=biblioloo.biblionumber total_holds=biblioloo.total_holds split_data=b %]
</div>
[% END # /FOREACh b %]
[% END # /IF ( branchcodes.empty ) %]
[% END %]
[% END # /IF hold_branches.empty %]
[% ELSIF Koha.Preference('HoldsSplitQueue') == 'itemtype' %]
[% SET itemtypes = [] %]
[% FOREACH h IN biblioloo.reserveloop %]
[% SET hold_itemtype = h.object.item.effective_itemtype || h.itemtype %]
[% itemtypes.push( hold_itemtype ) %]
[% END %]
[% itemtypes = itemtypes.unique %]
[% IF ( itemtypes.empty ) %]
<div class="alert alert-info"> There are no holds on this title. </div>
[% IF biblioloo.hold_itemtypes.empty %]
<div class="holds_by_itemtype">
<h4>Any item type</h4>
[% INCLUDE holds_table.inc biblio_id=biblioloo.biblionumber total_holds=biblioloo.total_holds split_data="any" %]
</div>
[% ELSE %]
[% FOREACH i IN itemtypes.sort %]
[% SET holds_by_itemtype = [] %]
[% FOREACH h IN biblioloo.reserveloop %]
[% SET hold_itemtype = h.object.item.effective_itemtype || h.itemtype %]
[% IF hold_itemtype == i %]
[% holds_by_itemtype.push( h ) %]
[% END %]
[% END %]
[% FOREACH i IN biblioloo.hold_itemtypes %]
<div class="holds_by_itemtype">
[% IF i %]
[% IF i && i != 'any' %]
<h4>[% ItemTypes.GetDescription( i ) | html %]</h4>
[% ELSE %]
<h4>Any item type</h4>
[% END %]
[% INCLUDE holds_table.inc holds=holds_by_itemtype %]
[% INCLUDE holds_table.inc biblio_id=biblioloo.biblionumber total_holds=biblioloo.total_holds split_data=i %]
</div>
[% END # /FOREACH i %]
[% END # /IF ( itemtypes.empty ) %]
[% END %]
[% END # /IF hold_split.empty %]
[% ELSIF Koha.Preference('HoldsSplitQueue') == 'branch_itemtype' %]
[% SET branchcodes = [] %]
[% FOREACH h IN biblioloo.reserveloop %]
[% branchcodes.push( h.branchcode ) %]
[% END %]
[% branchcodes = branchcodes.unique %]
[% IF ( branchcodes.empty ) %]
<div class="alert alert-info"> There are no holds on this title. </div>
[% ELSE %]
[% FOREACH b IN branchcodes.sort %]
<div class="holds_by_library">
<h4 class="library_holds">[% Branches.GetName( b ) | html %]</h4>
[% SET holds_by_branch = [] %]
[% FOREACH h IN biblioloo.reserveloop %]
[% IF h.branchcode == b %]
[% holds_by_branch.push( h ) %]
[% FOREACH b IN biblioloo.hold_branches %]
<div class="holds_by_library">
<h4>[% Branches.GetName( b ) | html %]</h4>
[% FOREACH i IN biblioloo.hold_itemtypes %]
<div class="holds_by_itemtype">
[% IF i && i != 'any' %]
<h4>[% ItemTypes.GetDescription( i ) | html %]</h4>
[% ELSE %]
<h4>Any item type</h4>
[% END %]
[% END %]
[% SET itemtypes = [] %]
[% FOREACH h IN holds_by_branch %]
[% SET hold_itemtype = h.object.item.effective_itemtype || h.itemtype %]
[% itemtypes.push( hold_itemtype ) %]
[% END %]
[% itemtypes = itemtypes.unique %]
[% FOREACH i IN itemtypes.sort %]
<div class="holds_by_itemtype">
<h5 class="itemtype_holds">
[% IF i %]
[% ItemTypes.GetDescription( i ) | html %]
[% ELSE %]
<span>Any item type</span>
[% END %]
</h5>
[% SET holds_by_itemtype = [] %]
[% FOREACH h IN holds_by_branch %]
[% SET hold_itemtype = h.object.item.effective_itemtype || h.itemtype %]
[% IF hold_itemtype == i %]
[% holds_by_itemtype.push( h ) %]
[% END %]
[% END %]
[% INCLUDE holds_table.inc holds=holds_by_itemtype %]
</div>
<!-- /.holds_by_itemtype -->
[% END %]
</div>
<!-- /.holds_by_library -->
[% END # /FOREACH b %]
[% END # /IF ( branchcodes.empty ) %]
[% ELSE %]
[% IF ( biblioloo.reserveloop.size ) %]
[% INCLUDE holds_table.inc holds=biblioloo.reserveloop %]
[% ELSE %]
<div class="alert alert-info"> There are no holds on this title. </div>
[% SET split_data = b _ "_" _ i %]
[% INCLUDE holds_table.inc biblio_id=biblioloo.biblionumber total_holds=biblioloo.total_holds split_data=split_data %]
</div>
[% END %]
</div>
[% END %]
[% ELSE %]
[% INCLUDE holds_table.inc biblio_id=biblioloo.biblionumber total_holds=biblioloo.total_holds split_data="any" %]
[% END # /IF HoldsSplitQueue %]
</div>
<!-- /hold_title -->
[% END # /IF biblioloo.reserveloop %]
[% ELSE %]
<div class="note"> There are no holds on this title. </div>
[% END # /IF ( biblioloo.total_holds ) %]
[% END # FOREACH biblioloo %]
</div>
</form>
@ -1605,6 +1539,9 @@
[% INCLUDE 'datatables.inc' %]
[% INCLUDE 'calendar.inc' %]
[% INCLUDE 'select2.inc' %]
<script>
hold_table_settings = [% TablesSettings.GetTableSettings( 'circ', 'holds', 'patron_holds_table', 'json' ) | $raw %];
</script>
[% Asset.js("js/holds.js") | $raw %]
[% Asset.js("js/hold-group.js") | $raw %]
@ -1613,8 +1550,16 @@
[% SET url_biblio_params = url_biblio_params _ "&amp;multi_hold=1" %]
[% END %]
<script nonce="[% Koha.CSPNonce | $raw %]">
var hold_table_settings = [% TablesSettings.GetTableSettings( 'circ', 'holds', 'patron_holds_table', 'json' ) | $raw %];
var biblionumbers = [[% biblionumbers.join(', ') | $raw %]];
var hold_branches = {[% FOREACH biblio_info IN biblioloop %] [% biblio_info.biblionumber | html %]: ["[% biblio_info.hold_branches.join('", "') | $raw %]"], [% END %]};
var hold_itemtypes = {[% FOREACH biblio_info IN biblioloop %] [% biblio_info.biblionumber | html %]: ["[% biblio_info.hold_itemtypes.join('", "') | $raw %]"], [% END %]};
var HoldsSplitQueue = "[% Koha.Preference('HoldsSplitQueue') | html %]";
var HoldsSplitQueueNumbering = "[% Koha.Preference('HoldsSplitQueueNumbering') | html %]";
var SuspendHoldsIntranet = [% ( Koha.Preference('SuspendHoldsIntranet') ) ? 1 : 0 | html %];
var AutoResumeSuspendedHolds = [% ( Koha.Preference('AutoResumeSuspendedHolds') ) ? 1 : 0 | html %];
var AllowHoldDateInFuture = [% ( Koha.Preference('AllowHoldDateInFuture') ) ? 1 : 0 | html %];
var HidePatronName = [% ( Koha.Preference('HidePatronName') ) ? 1 : 0 | html %];
var CAN_user_reserveforothers_modify_holds_priority = [%CAN_user_reserveforothers_modify_holds_priority ? 1 : 0 | html %];
var borrowernumber = "[% patron.borrowernumber | $raw %]";
var patron_homebranch = "[% To.json( Branches.GetName( patron.branchcode ) ) | $raw %]";
var override_items = {[% FOREACH biblio_info IN biblioloop %][% FOREACH itemloo IN biblio_info.itemloop %][% IF ( itemloo.override ) %]
@ -1664,11 +1609,36 @@
$.fn.select2.defaults.set("width", "100%");
$.fn.select2.defaults.set("dropdownAutoWidth", true);
$(document).ready(function () {
$("#cancellation-reason-div").hide();
$(".rank-request").on("change", function () {
if ($(".rank-request option:selected[value='del']").length) {
$("#cancellation-reason-div").show();
$(document).ready(function() {
biblionumbers.forEach(function(biblionumber) {
let branches = hold_branches[biblionumber];
let itemtypes = hold_itemtypes[biblionumber];
switch (HoldsSplitQueue) {
case 'branch':
branches.forEach(function(branch) {
load_patron_holds_table(biblionumber, {name: HoldsSplitQueue, value: branch});
});
break;
case 'itemtype':
itemtypes.forEach(function(itemtype) {
load_patron_holds_table(biblionumber, {name: HoldsSplitQueue, value: itemtype});
});
break;
case 'branch_itemtype':
branches.forEach(function(branch) {
itemtypes.forEach(function(itemtype) {
load_patron_holds_table(biblionumber, {name: HoldsSplitQueue, value: branch + '_' + itemtype});
});
});
break;
default:
load_patron_holds_table(biblionumber, {name: 'any', value: 'any'});
}
});
$('#cancellation-reason-div').hide();
$('.rank-request').on('change', function() {
if ( $(".rank-request option:selected[value='del']").length ) {
$('#cancellation-reason-div').show();
} else {
$("#cancellation-reason-div").hide();
}
@ -2025,66 +1995,11 @@
});
}
$(".hold-arrow").click(function (e) {
e.preventDefault();
let arrowForm = $("#hold-actions-form").attr({
action: "request.pl",
method: "post",
});
let arrow_op = $("<input />").attr({
name: "op",
type: "hidden",
value: $(this).data("op"),
});
let arrow_where = $("<input />").attr({
name: "where",
type: "hidden",
value: $(this).data("where"),
});
let arrow_fp = $("<input />").attr({
name: "first_priority",
type: "hidden",
value: $(this).data("first_priority"),
});
let arrow_lp = $("<input />").attr({
name: "last_priority",
type: "hidden",
value: $(this).data("last_priority"),
});
let arrow_pp = $("<input />").attr({
name: "prev_priority",
type: "hidden",
value: $(this).data("prev_priority"),
});
let arrow_np = $("<input />").attr({
name: "next_priority",
type: "hidden",
value: $(this).data("next_priority"),
});
let arrow_bn = $("<input />").attr({
name: "borrowernumber",
type: "hidden",
value: $(this).data("borrowernumber"),
});
let arrow_bb = $("<input />").attr({
name: "biblionumber",
type: "hidden",
value: $(this).data("biblionumber"),
});
let arrow_ri = $("<input />").attr({
name: "reserve_id",
type: "hidden",
value: $(this).data("reserve_id"),
});
let arrow_date = $("<input />").attr({
name: "date",
type: "hidden",
value: $(this).data("date"),
});
arrowForm.append(arrow_op, arrow_where, arrow_fp, arrow_lp, arrow_pp, arrow_np, arrow_bn, arrow_bb, arrow_ri, arrow_date);
$("#hold-actions-form").submit();
return true;
});
if(!localStorage.selectedHolds || document.referrer.replace(/\?.*/, '') !== document.location.origin+document.location.pathname) {
localStorage.selectedHolds = [];
}
});
</script>
<script nonce="[% Koha.CSPNonce | $raw %]">
@ -2100,13 +2015,6 @@
});
</script>
[% END %]
<script nonce="[% Koha.CSPNonce | $raw %]">
$(".printholdslip").click(function () {
var reserve_id = $(this).attr("data-reserve_id");
window.open("/cgi-bin/koha/circ/hold-transfer-slip.pl?reserve_id=" + reserve_id);
return false;
});
</script>
[% END %]
[% INCLUDE 'intranet-bottom.inc' %]

View File

@ -1456,6 +1456,9 @@ function update_search_description(
emptyTable: options.emptyTable
? options.emptyTable
: __("No data available in table"),
infoFiltered: options.infoFiltered
? options.infoFiltered
: __("(filtered from _MAX_ total entries)"),
},
},
options

File diff suppressed because it is too large Load Diff

View File

@ -669,9 +669,13 @@ if ( ( $findborrower && $borrowernumber_hold || $findclub && $club_hold )
# existingreserves building
my @reserveloop;
my $total_holds = 0;
my $hold_branches = [];
my $hold_itemtypes = [];
my $always_show_holds = $input->cookie('always_show_holds');
$template->param( always_show_holds => $always_show_holds );
my $show_holds_now = $input->param('show_holds_now');
unless ( ( defined $always_show_holds && $always_show_holds eq 'DONT' ) && !$show_holds_now ) {
my $holds_count_per_patron = {
map { $_->{borrowernumber} => $_->{hold_count} } @{ Koha::Holds->search(
@ -684,64 +688,27 @@ if ( ( $findborrower && $borrowernumber_hold || $findclub && $club_hold )
)->unblessed
}
};
my @reserves = Koha::Holds->search(
{ 'me.biblionumber' => $biblionumber },
{ prefetch => [ 'borrowernumber', 'itemnumber' ], order_by => 'priority' }
)->as_list;
foreach my $res (
sort {
my $a_found = $a->found() || '';
my $b_found = $a->found() || '';
$a_found cmp $b_found;
} @reserves
)
{
my %reserve;
if ( $res->is_found() ) {
$reserve{'holdingbranch'} = $res->item()->holdingbranch();
$reserve{'biblionumber'} = $res->item()->biblionumber();
$reserve{'barcodenumber'} = $res->item()->barcode();
$reserve{'wbrcode'} = $res->branchcode();
$reserve{'itemnumber'} = $res->itemnumber();
$reserve{'wbrname'} = $res->branch()->branchname();
$reserve{'atdestination'} = $res->is_at_destination();
$reserve{'desk_name'} = ( $res->desk() ) ? $res->desk()->desk_name() : '';
$reserve{'found'} = $res->is_found();
$reserve{'inprocessing'} = $res->is_in_processing();
$reserve{'intransit'} = $res->is_in_transit();
} elsif ( $res->priority() > 0 ) {
if ( my $item = $res->item() ) {
$reserve{'itemnumber'} = $item->id();
$reserve{'barcodenumber'} = $item->barcode();
$reserve{'item_level_hold'} = 1;
}
$total_holds = Koha::Holds->search( { biblionumber => $biblionumber } )->count;
my $branches = Koha::Holds->search(
{
biblionumber => $biblionumber,
},
{
select => [ { distinct => 'branchcode' } ],
as => [qw( branchcode )],
}
$reserve{'expirationdate'} = $res->expirationdate;
$reserve{'date'} = $res->reservedate;
$reserve{'borrowernumber'} = $res->borrowernumber();
$reserve{'biblionumber'} = $res->biblionumber();
$reserve{'patron'} = $res->borrower;
$reserve{'notes'} = $res->reservenotes();
$reserve{'waiting_date'} = $res->waitingdate();
$reserve{'ccode'} = $res->item() ? $res->item()->ccode() : undef;
$reserve{'barcode'} = $res->item() ? $res->item()->barcode() : undef;
$reserve{'priority'} = $res->priority();
$reserve{'lowestPriority'} = $res->lowestPriority();
$reserve{'suspend'} = $res->suspend();
$reserve{'suspend_until'} = $res->suspend_until();
$reserve{'reserve_id'} = $res->reserve_id();
$reserve{itemtype} = $res->itemtype();
$reserve{branchcode} = $res->branchcode();
$reserve{non_priority} = $res->non_priority();
$reserve{object} = $res;
$reserve{hold_group_id} = $res->hold_group_id;
if ( $holds_count_per_patron->{ $reserve{'borrowernumber'} } == 1 ) {
$reserve{'change_hold_type_allowed'} = 1;
)->unblessed;
$hold_branches = [ map { $_->{branchcode} } @$branches ];
my $itemtypes = Koha::Holds->search(
{
biblionumber => $biblionumber,
},
{
select => [ { distinct => 'itemtype' } ],
as => [qw( itemtype )],
}
push( @reserveloop, \%reserve );
}
)->unblessed;
$hold_itemtypes = [ map { $_->{itemtype} ? $_->{itemtype} : 'any' } @$itemtypes ];
}
# get the time for the form name...
@ -764,11 +731,14 @@ if ( ( $findborrower && $borrowernumber_hold || $findclub && $club_hold )
C4::Search::enabled_staff_search_views,
);
$biblioloopiter{biblionumber} = $biblionumber;
$biblioloopiter{title} = $biblio->title;
$biblioloopiter{author} = $biblio->author;
$biblioloopiter{rank} = $fixedRank;
$biblioloopiter{reserveloop} = \@reserveloop;
$biblioloopiter{biblionumber} = $biblionumber;
$biblioloopiter{title} = $biblio->title;
$biblioloopiter{author} = $biblio->author;
$biblioloopiter{rank} = $fixedRank;
$biblioloopiter{reserveloop} = \@reserveloop;
$biblioloopiter{total_holds} = $total_holds;
$biblioloopiter{hold_branches} = $hold_branches;
$biblioloopiter{hold_itemtypes} = $hold_itemtypes;
# Pass through any reserve charge
if ($patron) {
@ -791,6 +761,8 @@ if ( ( $findborrower && $borrowernumber_hold || $findclub && $club_hold )
$template->param( reserveloop => \@reserveloop );
}
$template->param( total_holds => $total_holds );
if ( $patron && $multi_hold ) {
# Add the valid pickup locations