View | Details | Raw Unified | Return to bug 23269
Collapse All | Expand All

(-)a/Koha/Hold.pm (+18 lines)
Lines 783-788 sub is_suspended { Link Here
783
    return $self->suspend();
783
    return $self->suspend();
784
}
784
}
785
785
786
=head3 item_level_holds
787
788
Returns the number (count) of item-level holds for this hold's biblionumber and patron
789
790
=cut
791
792
sub item_level_holds {
793
    my ($self) = @_;
794
795
    return Koha::Holds->search(
796
        {
797
            biblionumber   => $self->biblionumber,
798
            borrowernumber => $self->borrowernumber,
799
            itemnumber     => { '!=', undef },
800
        }
801
    )->count;
802
}
803
786
=head3 add_cancellation_request
804
=head3 add_cancellation_request
787
805
788
    my $cancellation_request = $hold->add_cancellation_request({ [ creation_date => $creation_date ] });
806
    my $cancellation_request = $hold->add_cancellation_request({ [ creation_date => $creation_date ] });
(-)a/Koha/REST/V1/Holds.pm (-10 / +16 lines)
Lines 281-301 sub edit { Link Here
281
        }
281
        }
282
282
283
        $pickup_library_id //= $hold->branchcode;
283
        $pickup_library_id //= $hold->branchcode;
284
        my $priority        = $body->{priority}        // $hold->priority;
284
        my $priority        = $body->{priority} // $hold->priority;
285
        my $hold_date       = $body->{hold_date}       // $hold->reservedate;
285
        my $hold_date       = exists $body->{hold_date}       ? $body->{hold_date}       : $hold->reservedate;
286
        my $expiration_date = $body->{expiration_date} // $hold->expirationdate;
286
        my $expiration_date = exists $body->{expiration_date} ? $body->{expiration_date} : $hold->expirationdate;
287
        my $item_id         = exists $body->{item_id}         ? $body->{item_id}         : $hold->itemnumber;
288
        my $item_level =
289
            exists $body->{item_level}
290
            ? ( $body->{item_level} ? 1 : 0 )
291
            : $hold->item_level_hold;
287
292
288
        # suspended_until can also be set to undef
293
        # suspended_until can also be set to undef
289
        my $suspended_until = $body->{suspended_until} || $hold->suspend_until;
294
        my $suspended_until = $body->{suspended_until} || $hold->suspend_until;
290
295
291
        my $params = {
296
        my $params = {
292
            reserve_id     => $hold->id,
297
            reserve_id      => $hold->id,
293
            branchcode     => $pickup_library_id,
298
            branchcode      => $pickup_library_id,
294
            rank           => $priority,
299
            rank            => $priority,
295
            suspend_until  => $suspended_until,
300
            suspend_until   => $suspended_until,
296
            itemnumber     => $hold->itemnumber,
301
            itemnumber      => $item_id,
297
            reservedate    => $hold_date,
302
            reservedate     => $hold_date,
298
            expirationdate => $expiration_date,
303
            expirationdate  => $expiration_date,
304
            item_level_hold => $item_level
299
        };
305
        };
300
306
301
        C4::Reserves::ModReserve($params);
307
        C4::Reserves::ModReserve($params);
(-)a/admin/columns_settings.yml (+1 lines)
Lines 2129-2134 modules: Link Here
2129
              columnname: action
2129
              columnname: action
2130
2130
2131
      patron_holds_table:
2131
      patron_holds_table:
2132
        default_sort_order: 1
2132
        columns:
2133
        columns:
2133
            -
2134
            -
2134
              columnname: checkbox
2135
              columnname: checkbox
(-)a/api/v1/swagger/definitions/hold.yaml (+10 lines)
Lines 114-119 properties: Link Here
114
  item_level:
114
  item_level:
115
    type: boolean
115
    type: boolean
116
    description: If the hold is placed at item level
116
    description: If the hold is placed at item level
117
  item_level_holds:
118
    type: 
119
      - integer
120
      - "null"
121
    description: Count of item level holds for this bibliographic record
117
  cancellation_requested:
122
  cancellation_requested:
118
    type:
123
    type:
119
      - boolean
124
      - boolean
Lines 134-139 properties: Link Here
134
      - object
139
      - object
135
      - "null"
140
      - "null"
136
    description: The item
141
    description: The item
142
  item_group:
143
    type:
144
      - object
145
      - "null"
146
    description: The item group
137
  pickup_library:
147
  pickup_library:
138
    type:
148
    type:
139
      - object
149
      - object
(-)a/api/v1/swagger/paths/holds.yaml (-2 / +18 lines)
Lines 108-113 Link Here
108
            - pickup_library
108
            - pickup_library
109
            - item
109
            - item
110
            - patron
110
            - patron
111
            - item_group
112
            - item_level_holds
111
        collectionFormat: csv
113
        collectionFormat: csv
112
    produces:
114
    produces:
113
      - application/json
115
      - application/json
Lines 430-441 Link Here
430
              format: date-time
432
              format: date-time
431
            hold_date:
433
            hold_date:
432
              description: Hold date
434
              description: Hold date
433
              type: string
435
              type:
436
                - string
437
                - "null"
434
              format: date
438
              format: date
435
            expiration_date:
439
            expiration_date:
436
              description: Hold's expiration date
440
              description: Hold's expiration date
437
              type: string
441
              type:
442
                - string
443
                - "null"
438
              format: date
444
              format: date
445
            item_id:
446
              description: Internal item identifier
447
              type:
448
                - integer
449
                - "null"
450
            item_level:
451
              description: Whether the hold is item-level or not
452
              type:
453
                - boolean
454
                - "null"
439
          additionalProperties: false
455
          additionalProperties: false
440
    consumes:
456
    consumes:
441
      - application/json
457
      - application/json
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/holds_table.inc (-360 / +6 lines)
Lines 2-380 Link Here
2
[% SET hold_cancellation = AuthorisedValues.GetAuthValueDropbox('HOLD_CANCELLATION') %]
2
[% SET hold_cancellation = AuthorisedValues.GetAuthValueDropbox('HOLD_CANCELLATION') %]
3
[% USE AuthorisedValues %]
3
[% USE AuthorisedValues %]
4
4
5
<table id="patron_holds_table" class="holds_table">
5
[%#This include depends on the asset js/form-submit.js. Any template making use of this include must import form-submit.js as well. %]
6
[%#FIXME can form-submit.js be imported into this file directly? %]
7
8
<table id="patron_holds_table_[% biblio_id | html %]_[% split_data | html %]" class="holds_table" data-total-holds="[% total_holds | html %]">
6
    <thead>
9
    <thead>
7
        <tr>
10
        <tr>
8
            <th id="checkbox" data-colname="checkbox"><input type="checkbox" class="select_hold_all" /></th>
11
            <th id="checkbox" data-colname="checkbox"><input type="checkbox" class="select_hold_all" /></th>
9
            <th id="priority" data-colname="priority">Priority</th>
12
            <th id="priority" data-colname="priority">Priority</th>
10
            [% IF ( CAN_user_reserveforothers_modify_holds_priority ) %]
13
            <th id="change_priority" data-colname="change_priority">Change priority</th>
11
                <th id="change_priority" data-colname="change_priority">Change priority</th>
12
            [% END %]
13
            <th id="patron" data-colname="patron">Patron</th>
14
            <th id="patron" data-colname="patron">Patron</th>
14
            <th id="notes" data-colname="notes">Notes</th>
15
            <th id="notes" data-colname="notes">Notes</th>
15
            <th id="date" data-colname="date">Date</th>
16
            <th id="date" data-colname="date">Date</th>
16
            <th id="expiration" data-colname="expiration">Expiration</th>
17
            <th id="expiration" data-colname="expiration">Expiration</th>
17
            <th id="pickup_library" data-colname="pickup_library">Pickup library</th>
18
            <th id="pickup_library" data-colname="pickup_library">Pickup library</th>
18
            <th id="details" data-colname="details">Details</th>
19
            <th id="details" data-colname="details">Details</th>
19
            [% IF ( CAN_user_reserveforothers_modify_holds_priority ) %]
20
            <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>
20
                <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>
21
            [% END %]
22
            <th id="delete" data-colname="delete">Delete</th>
21
            <th id="delete" data-colname="delete">Delete</th>
23
            <th id="suspend" data-colname="suspend">Suspend</th>
22
            <th id="suspend" data-colname="suspend">Suspend</th>
24
            <th id="print_slip" data-colname="print_slip">Print hold/transfer slip</th>
23
            <th id="print_slip" data-colname="print_slip">Print hold/transfer slip</th>
25
        </tr>
24
        </tr>
26
    </thead>
25
    </thead>
27
    [%- SET first_priority = 0 -%]
28
    [%- SET found_holds = 0 -%]
29
    [%- SET last_priority  = holds.last.priority -%]
30
31
    [% SET all_priorities = [] %]
32
    [% FOREACH hold IN holds %]
33
        [% all_priorities.push( hold.priority ) %]
34
    [% END %]
35
36
    <tbody>
37
        [% FOREACH hold IN holds %]
38
            [%- IF !hold.found && first_priority == 0 -%]
39
                [%- first_priority = hold.priority -%]
40
                [%- found_holds = loop.index() -%]
41
            [%- END -%]
42
            [%- IF Koha.Preference('HoldsSplitQueueNumbering') == 'actual' -%]
43
                [%- this_priority = hold.priority -%]
44
            [%- ELSE -%]
45
                [%- this_priority = loop.count() - found_holds -%]
46
            [%- END -%]
47
            [% SET tr_class = hold.suspend ? 'suspend' : '' %]
48
            <tr class="[% tr_class | html %]">
49
                <td
50
                    ><input
51
                        type="checkbox"
52
                        class="select_hold"
53
                        data-id="[% hold.reserve_id | html %]"
54
                        data-item_level_hold="[% hold.item_level_hold | html %]"
55
                        data-itemnumber="[% hold.itemnumber | html %]"
56
                        data-biblionumber="[% hold.biblionumber | html %]"
57
                        data-waiting="[% hold.atdestination | html %]"
58
                        data-intransit="[% hold.intransit | html %]"
59
                /></td>
60
                <td style="min-width:185px;" data-order="[% priority | html %]">
61
                    <div>
62
                        <input type="hidden" name="reserve_id" value="[% hold.reserve_id | html %]" />
63
                        <input type="hidden" name="borrowernumber" value="[% hold.borrowernumber | html %]" />
64
                        <input type="hidden" name="biblionumber" value="[% hold.biblionumber | html %]" />
65
                        [% IF ( CAN_user_reserveforothers_modify_holds_priority ) %]
66
                            [% IF Koha.Preference('HoldsSplitQueue') == "nothing" && !hold.found %]
67
                                <label for="rank-request_[% hold.reserve_id | html %]">Change priority to:</label>
68
                                <select name="rank-request" id="rank-request_[% hold.reserve_id | html %]" class="rank-request" data-hold-id="[% hold.reserve_id | html %]">
69
                                    [% IF ( CAN_user_reserveforothers_modify_holds_priority ) %]
70
                                        [% FOREACH priority IN all_priorities %]
71
                                            [% IF priority == this_priority %]
72
                                                <option value="[% priority | html %]" selected="selected">[% priority | html %]</option>
73
                                            [% ELSIF priority > 0 %]
74
                                                <option value="[% priority | html %]">[% priority | html %]</option>
75
                                            [% END %]
76
                                        [% END %]
77
                                    [% ELSE %]
78
                                        <option value="[% hold.priority | html %]" selected="selected">[% this_priority | html %]</option>
79
                                    [% END %]
80
                                    <option value="del">del</option>
81
                                </select>
82
                            [% ELSE %]
83
                                <input type="hidden" name="rank-request" class="rank-request" value="[% hold.priority | html %]" data-hold-id="[% hold.reserve_id | html %]" />
84
                                <select name="rank-request" class="rank-request" disabled="disabled" data-hold-id="[% hold.reserve_id | html %]">
85
                                    [% IF ( hold.found ) %]
86
                                        [% IF ( hold.intransit ) %]
87
                                            <option value="T" selected="selected">In transit</option>
88
                                        [% ELSIF (hold.inprocessing) %]
89
                                            <option value="P" selected="selected">In processing</option>
90
                                        [% ELSE %]
91
                                            <option value="W" selected="selected">Waiting</option>
92
                                        [% END %]
93
                                    [% ELSE %]
94
                                        <option value="[% hold.priority | html %]" selected="selected">[% this_priority | html %]</option>
95
                                    [% END %]
96
                                </select>
97
                            [% END %]
98
                        [% ELSE %]
99
                            <input type="hidden" name="rank-request" class="rank-request" value="[% hold.priority | html %]" data-hold-id="[% hold.reserve_id | html %]" />
100
                        [% END %]
101
                        <div>
102
                            <label for="current_priority_[% hold.reserve_id | html %]">Current priority: </label>
103
                            <span id="current_priority_[% hold.reserve_id | html %]" class="current_priority badge text-bg-info">[% hold.priority | html %]</span>
104
                        </div>
105
                    </div>
106
                </td>
107
                [%- IF ( CAN_user_reserveforothers_modify_holds_priority ) -%]
108
                    [%- UNLESS hold.found -%]
109
                        [%- SET prev_priority  = loop.prev.priority -%]
110
                        [%- SET next_priority  = loop.next.priority -%]
111
                        <td style="white-space:nowrap;">
112
                            <a
113
                                class="hold-arrow"
114
                                title="Move hold up"
115
                                data-op="cud-move"
116
                                data-where="up"
117
                                data-first_priority="[% first_priority | html %]"
118
                                data-last_priority="[% last_priority | html %]"
119
                                data-prev_priority="[% prev_priority | html %]"
120
                                data-next_priority="[% next_priority | html %]"
121
                                data-borrowernumber="[% hold.borrowernumber | html %]"
122
                                data-biblionumber="[% hold.biblionumber | html %]"
123
                                data-reserve_id="[% hold.reserve_id | html %]"
124
                                data-date="[% hold.date | html %]"
125
                            >
126
                                <i class="fa fa-lg icon-move-hold-up" aria-hidden="true"></i>
127
                            </a>
128
129
                            <a
130
                                class="hold-arrow"
131
                                title="Move hold to top"
132
                                data-op="cud-move"
133
                                data-where="top"
134
                                data-first_priority="[% first_priority | html %]"
135
                                data-last_priority="[% last_priority | html %]"
136
                                data-prev_priority="[% prev_priority | html %]"
137
                                data-next_priority="[% next_priority | html %]"
138
                                data-borrowernumber="[% hold.borrowernumber | html %]"
139
                                data-biblionumber="[% hold.biblionumber | html %]"
140
                                data-reserve_id="[% hold.reserve_id | html %]"
141
                                data-date="[% hold.date | html %]"
142
                            >
143
                                <i class="fa fa-lg icon-move-hold-top" aria-hidden="true"></i>
144
                            </a>
145
146
                            <a
147
                                class="hold-arrow"
148
                                title="Move hold to bottom"
149
                                data-op="cud-move"
150
                                data-where="bottom"
151
                                data-first_priority="[% first_priority | html %]"
152
                                data-last_priority="[% last_priority | html %]"
153
                                data-prev_priority="[% prev_priority | html %]"
154
                                data-next_priority="[% next_priority | html %]"
155
                                data-borrowernumber="[% hold.borrowernumber | html %]"
156
                                data-biblionumber="[% hold.biblionumber | html %]"
157
                                data-reserve_id="[% hold.reserve_id | html %]"
158
                                data-date="[% hold.date | html %]"
159
                            >
160
                                <i class="fa fa-lg icon-move-hold-bottom" aria-hidden="true"></i>
161
                            </a>
162
163
                            <a
164
                                class="hold-arrow"
165
                                title="Move hold down"
166
                                data-op="cud-move"
167
                                data-where="down"
168
                                data-first_priority="[% first_priority | html %]"
169
                                data-last_priority="[% last_priority | html %]"
170
                                data-prev_priority="[% prev_priority | html %]"
171
                                data-next_priority="[% next_priority | html %]"
172
                                data-borrowernumber="[% hold.borrowernumber | html %]"
173
                                data-biblionumber="[% hold.biblionumber | html %]"
174
                                data-reserve_id="[% hold.reserve_id | html %]"
175
                                data-date="[% hold.date | html %]"
176
                            >
177
                                <i class="fa fa-lg icon-move-hold-down" aria-hidden="true"></i>
178
                            </a>
179
                        </td>
180
                    [%- ELSE -%]
181
                        <td></td>
182
                    [%- END -%]
183
                [%- END -%]
184
                <td> [% INCLUDE 'patron-title.inc' patron=hold.patron hide_patron_infos_if_needed=1 %] </td>
185
                <td>[% hold.notes | html | html_line_break %]</td>
186
                <td data-order="[% hold.date| html %]">
187
                    [% IF Koha.Preference('AllowHoldDateInFuture') %]
188
                        <input type="text" class="flatpickr" value="[% hold.date | html %]" required="required" size="10" name="reservedate" />
189
                    [% ELSE %]
190
                        [% hold.date | $KohaDates %]
191
                    [% END %]
192
                </td>
193
                <td>
194
                    <input type="text" class="flatpickr" data-flatpickr-futuredate="true" value="[% hold.expirationdate | html %]" size="10" name="expirationdate" />
195
                </td>
196
                <td>
197
                    [%- IF ( hold.found ) -%]
198
                        <input type="hidden" name="pickup" value="[% hold.wbrcode | html %]" />
199
                        [%- IF ( hold.atdestination ) -%]
200
                            Item waiting at <strong> [% hold.wbrname | html %]</strong>[% IF hold.desk_name %], [% hold.desk_name | html %],[% END %] since [% hold.waiting_date | $KohaDates %]
201
                        [%- ELSIF (hold.intransit) -%]
202
                            Item being transferred to <strong> [% hold.wbrname | html %]</strong>
203
                        [%- ELSIF (hold.inprocessing) -%]
204
                            Item being processed at <strong> [% hold.wbrname | html %]</strong>
205
                        [%- ELSE -%]
206
                            Hold expected at <strong>[% hold.wbrname | html %]</strong>, please checkin to verify status
207
                        [%- END -%]
208
                    [%- ELSE -%]
209
                        [%- IF Koha.Preference('IndependentBranches') && Branches.all().size == 1 -%]
210
                            [% Branches.GetName(hold.branchcode) | html %] <input type="hidden" name="pickup" value="[% hold.branchcode | html %]" />
211
                        [%- ELSE -%]
212
                            <select class="pickup_location_dropdown" data-selected="[% hold.branchcode | html %]" data-hold-id="[% hold.reserve_id | html %]" data-pickup-location-source="hold" name="pickup">
213
                                <option selected="selected" value="[% hold.branchcode | html %]">[% Branches.GetName(hold.branchcode) | html %]</option>
214
                                <option value="" disabled="disabled" class="loading">Loading...</option>
215
                            </select>
216
                            <img class="loading_[% hold.reserve_id | html %]" src="[% interface | html %]/[% theme | html %]/img/spinner-small.gif" alt="" style="display:none;" />
217
                        [%- END -%]
218
                    [%- END -%]
219
                </td>
220
                <td>
221
                    [%- IF ( hold.found ) -%]
222
                        <a href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=[% hold.biblionumber | uri %]&amp;itemnumber=[% hold.itemnumber | uri %]#item[% hold.itemnumber | uri %]">
223
                            [%- IF ( hold.barcodenumber ) -%]
224
                                [%- hold.barcodenumber | html -%]
225
                            [%- ELSE -%]
226
                                <span>No barcode</span>
227
                            [%- END -%]
228
                            <input type="hidden" name="itemnumber" value="[% hold.itemnumber | html %]" />
229
                        </a>
230
                    [%- ELSE -%]
231
                        [%- IF ( hold.item_level_hold ) -%]
232
                            <em>
233
                                [%- IF ! hold.change_hold_type_allowed -%]
234
                                    <span>Only item</span>
235
                                    <a href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=[% hold.biblionumber | uri %]&amp;itemnumber=[% hold.itemnumber | uri %]#item[% hold.itemnumber | uri %]">
236
                                        [%- IF ( hold.barcodenumber ) -%]
237
                                            [%- hold.barcodenumber | html -%]
238
                                        [%- ELSE -%]
239
                                            <span>No barcode</span>
240
                                        [%- END -%]
241
                                        <input type="hidden" name="itemnumber" value="[% hold.itemnumber | html %]" />
242
                                    </a>
243
                                [%- ELSE -%]
244
                                    <select name="change_hold_type_[% hold.reserve_id | html %]">
245
                                        <option selected="selected" value="">
246
                                            [%- IF ( hold.barcodenumber ) -%]
247
                                                [% tx("Only item {barcode}", {barcode = hold.barcodenumber}) | html %]
248
                                            [%- ELSE -%]
249
                                                [% t("Only item [No barcode]") | html %]
250
                                            [%- END -%]
251
                                        </option>
252
                                        <option value="1">Next available</option>
253
                                    </select>
254
                                    [%- IF ( hold.itemnumber ) -%]
255
                                        <input type="hidden" name="itemnumber" value="[% hold.itemnumber | html %]" />
256
                                    [%- END -%]
257
                                    [%- IF hold.itemtype -%]
258
                                        <span style="display:none">Next available [% ItemTypes.GetDescription( hold.itemtype ) | html %] item</span>
259
                                    [%- ELSE -%]
260
                                        <span style="display:none">Next available</span>
261
                                    [%- END -%]
262
                                [%- END -%]
263
                            </em>
264
                        [%- ELSE -%]
265
                            [%- IF hold.itemtype -%]
266
                                <em>Next available [% ItemTypes.GetDescription( hold.itemtype ) | html %] item</em>
267
                            [%- ELSIF hold.object.item_group -%]
268
                                <em>Next available item from group <strong>[% hold.object.item_group.description | html %]</strong></em>
269
                            [%- ELSE -%]
270
                                <em>Next available</em>
271
                            [%- END -%]
272
273
                            <input type="hidden" name="itemnumber" value="" />
274
                        [%- END -%]
275
                    [%- END -%]
276
                    [%- IF hold.non_priority -%]
277
                        <br /><i>Non priority hold</i>
278
                    [%- END -%]
279
                    [%- IF hold.hold_group_id -%]
280
                        <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>
281
                    [%- END -%]
282
                </td>
283
                [%- IF ( CAN_user_reserveforothers_modify_holds_priority ) -%]
284
                    [%- UNLESS hold.found -%]
285
                        <td>
286
                            [% IF ( hold.lowestPriority ) %]
287
                                <a
288
                                    class="hold-arrow"
289
                                    title="Remove lowest priority"
290
                                    data-op="cud-setLowestPriority"
291
                                    data-borrowernumber="[% hold.borrowernumber | html %]"
292
                                    data-biblionumber="[% hold.biblionumber | html %]"
293
                                    data-reserve_id="[% hold.reserve_id | html %]"
294
                                    data-date="[% hold.date | html %]"
295
                                >
296
                                    <i class="fa fa-lg fa-rotate-90 icon-unset-lowest" aria-hidden="true"></i>
297
                                </a>
298
                            [% ELSE %]
299
                                <a
300
                                    class="hold-arrow"
301
                                    title="Set lowest priority"
302
                                    data-op="cud-setLowestPriority"
303
                                    data-borrowernumber="[% hold.borrowernumber | html %]"
304
                                    data-biblionumber="[% hold.biblionumber | html %]"
305
                                    data-reserve_id="[% hold.reserve_id | html %]"
306
                                    data-date="[% hold.date | html %]"
307
                                >
308
                                    <i class="fa fa-lg fa-rotate-90 icon-set-lowest" aria-hidden="true"></i>
309
                                </a>
310
                            [% END %]
311
                        </td>
312
                    [%- ELSE -%]
313
                        <td></td>
314
                    [%- END -%]
315
                [%- END -%]
316
                <td>
317
                    <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="#">
318
                        <i class="fa fa-trash" aria-label="Cancel hold"></i>
319
                    </a>
320
                </td>
321
                <td>
322
                    [% IF Koha.Preference('SuspendHoldsIntranet') %]
323
                        [% UNLESS ( hold.found ) %]
324
                            [% IF ( hold.suspend ) %]
325
                                <button class="btn btn-default btn-xs unsuspend-hold" data-reserve-id="[% hold.reserve_id | html %]" data-biblionumber="[% hold.biblionumber | html %]">
326
                                    <i class="fa fa-play" aria-hidden="true"></i> Unsuspend
327
                                </button>
328
                            [% ELSE %]
329
                                <button class="btn btn-default btn-xs suspend-hold" data-reserve-id="[% hold.reserve_id | html %]" data-biblionumber="[% hold.biblionumber | html %]">
330
                                    <i class="fa fa-pause" aria-hidden="true"></i> Suspend
331
                                </button>
332
                            [% END %]
333
334
                            [% IF Koha.Preference('AutoResumeSuspendedHolds') %]
335
                                <label for="suspend_until_[% hold.reserve_id | html %]">[% IF ( hold.suspend ) %]on[% ELSE %]until[% END %]</label>
336
                                <input
337
                                    type="text"
338
                                    name="suspend_until_[% hold.reserve_id | html %]"
339
                                    id="suspend_until_[% hold.reserve_id | html %]"
340
                                    size="10"
341
                                    value="[% hold.suspend_until | html %]"
342
                                    class="flatpickr"
343
                                    data-flatpickr-futuredate="true"
344
                                />
345
                            [%- ELSE -%]
346
                                <input type="hidden" name="suspend_until_[% hold.reserve_id | html %]" id="suspend_until_[% hold.reserve_id | html %]" value="" />
347
                            [%- END -%]
348
                        [%- END -%]
349
                    [%- END # IF SuspendHoldsIntranet -%]
350
                    [%- IF ( hold.found ) -%]
351
                        <a
352
                            class="btn btn-default  submit-form-link"
353
                            href="#"
354
                            id="revert_hold_[% hold.reserve_id | html %]"
355
                            data-op="cud-move"
356
                            data-where="down"
357
                            data-first_priority="[% first_priority | html %]"
358
                            data-last_priority="[% last_priority | html %]"
359
                            data-prev_priority="0"
360
                            data-next_priority="1"
361
                            data-borrowernumber="[% hold.borrowernumber | html %]"
362
                            data-biblionumber="[% hold.biblionumber | html %]"
363
                            data-itemnumber="[% hold.itemnumber | html %]"
364
                            data-reserve_id="[% hold.reserve_id | html %]"
365
                            data-date="[% hold.date | html %]"
366
                            data-action="request.pl"
367
                            data-method="post"
368
                            >[% IF hold.intransit %]Revert transit status[% ELSE %]Revert waiting status[% END %]</a
369
                        >
370
                    [%- END -%]
371
                </td>
372
                [% IF ( hold.intransit || hold.atdestination ) %]
373
                    <td><input class="printholdslip" type="button" name="printholdslip" value="Print slip" data-reserve_id="[% hold.reserve_id | html %]" /></td>
374
                [% ELSE %]
375
                    <td></td>
376
                [% END %]
377
            </tr>
378
        [% END %]
379
    </tbody>
380
</table>
26
</table>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt (-185 / +83 lines)
Lines 1276-1282 Link Here
1276
                [% END %]
1276
                [% END %]
1277
            [% END %]
1277
            [% END %]
1278
        [% END %]
1278
        [% END %]
1279
        [% IF ( reserveloop ) %]
1279
        [% IF ( total_holds ) %]
1280
            <form id="existing_holds" name="T[% time | html %]" action="modrequest.pl" method="post" style="display:block">
1280
            <form id="existing_holds" name="T[% time | html %]" action="modrequest.pl" method="post" style="display:block">
1281
                [% INCLUDE 'csrf-token.inc' %]
1281
                [% INCLUDE 'csrf-token.inc' %]
1282
                [% IF ( multi_hold ) %]
1282
                [% IF ( multi_hold ) %]
Lines 1295-1305 Link Here
1295
                <h2>Existing holds</h2>
1295
                <h2>Existing holds</h2>
1296
                <div id="toolbar" class="btn-toolbar sticky">
1296
                <div id="toolbar" class="btn-toolbar sticky">
1297
                    <div class="btn-group">
1297
                    <div class="btn-group">
1298
                        <input type="hidden" name="op" value="cud-modifyall" />
1298
                        <button class="btn cancel_selected_holds" data-bulk="true"></button>
1299
                        <input type="submit" class="btn btn-primary" name="submit" value="Update hold(s)" />
1300
                    </div>
1301
                    <div class="btn-group">
1302
                        <button class="btn cancel_selected_holds" data-bulk="true"> Cancel selected (<span class="selected_holds_count"></span>)</button>
1303
                    </div>
1299
                    </div>
1304
                    <div id="cancellation-reason-div" style="display:none">
1300
                    <div id="cancellation-reason-div" style="display:none">
1305
                        [% SET hold_cancellation = AuthorisedValues.GetAuthValueDropbox('HOLD_CANCELLATION') %]
1301
                        [% SET hold_cancellation = AuthorisedValues.GetAuthValueDropbox('HOLD_CANCELLATION') %]
Lines 1325-1461 Link Here
1325
                </div>
1321
                </div>
1326
                <div class="page-section">
1322
                <div class="page-section">
1327
                    [% FOREACH biblioloo IN biblioloop %]
1323
                    [% FOREACH biblioloo IN biblioloop %]
1328
                        [% IF ( biblioloo.reserveloop ) %]
1324
                        [% IF ( biblioloo.total_holds ) %]
1329
                            <div class="hold_title" id="hold_title_[% biblioloo.biblionumber | html %]">
1325
                            <div class="hold_title" id="hold_title_[% biblioloo.biblionumber | html %]">
1330
                                [% IF ( multi_hold ) %]
1326
                                [% IF ( multi_hold ) %]
1331
                                    <h3>
1327
                                    <h3>
1332
                                        <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% biblioloo.biblionumber | uri %]"> [% biblioloo.title | html %] </a>
1328
                                        <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% biblioloo.biblionumber | uri %]"> [% biblioloo.title | html %] </a>
1333
                                        <span class="badge bg-info-subtle"><span>[% biblioloo.reserveloop.size | html %] [% tn('Hold', 'Holds', biblioloo.reserveloop.size) | $raw %]</span></span>
1329
                                        <span class="badge bg-info-subtle"><span>[% biblioloo.total_holds | html %] [% tn('Hold', 'Holds', biblioloo.total_holds) | $raw %]</span></span>
1334
                                    </h3>
1330
                                    </h3>
1335
                                [% END %]
1331
                                [% END %]
1336
1332
1337
                                [% IF Koha.Preference('HoldsSplitQueue') == 'branch' %]
1333
                                [% IF Koha.Preference('HoldsSplitQueue') == 'branch' %]
1338
1334
                                    [% IF biblioloo.hold_branches.empty %]
1339
                                    [% SET branchcodes = [] %]
1335
                                        <div class="holds_by_library">
1340
1336
                                            <h4>Any library</h4>
1341
                                    [% FOREACH h IN biblioloo.reserveloop %]
1337
                                            [% INCLUDE holds_table.inc biblio_id=biblioloo.biblionumber total_holds=biblioloo.total_holds split_data="any" %]
1342
                                        [% branchcodes.push( h.branchcode ) %]
1338
                                        </div>
1343
                                    [% END %]
1344
                                    [% branchcodes = branchcodes.unique %]
1345
                                    [% IF ( branchcodes.empty ) %]
1346
                                        <div class="alert alert-info"> There are no holds on this title. </div>
1347
                                    [% ELSE %]
1339
                                    [% ELSE %]
1348
1340
                                        [% FOREACH b IN biblioloo.hold_branches %]
1349
                                        [% FOREACH b IN branchcodes.sort %]
1350
                                            [% SET holds_by_branch = [] %]
1351
                                            [% FOREACH h IN biblioloo.reserveloop %]
1352
                                                [% IF h.branchcode == b %]
1353
                                                    [% holds_by_branch.push( h ) %]
1354
                                                [% END %]
1355
                                            [% END %]
1356
                                            <div class="holds_by_library">
1341
                                            <div class="holds_by_library">
1357
                                                <h4>[% Branches.GetName( b ) | html %]</h4>
1342
                                                <h4>[% Branches.GetName( b ) | html %]</h4>
1358
1343
1359
                                                [% INCLUDE holds_table.inc holds=holds_by_branch %]
1344
                                                [% INCLUDE holds_table.inc biblio_id=biblioloo.biblionumber total_holds=biblioloo.total_holds split_data=b %]
1360
                                            </div>
1345
                                            </div>
1361
                                        [% END # /FOREACh b %]
1346
                                        [% END %]
1362
                                    [% END # /IF ( branchcodes.empty ) %]
1347
                                    [% END # /IF hold_branches.empty %]
1363
                                [% ELSIF Koha.Preference('HoldsSplitQueue') == 'itemtype' %]
1348
                                [% ELSIF Koha.Preference('HoldsSplitQueue') == 'itemtype' %]
1364
1349
1365
                                    [% SET itemtypes = [] %]
1350
                                    [% IF biblioloo.hold_itemtypes.empty %]
1366
1351
                                        <div class="holds_by_itemtype">
1367
                                    [% FOREACH h IN biblioloo.reserveloop %]
1352
                                            <h4>Any item type</h4>
1368
                                        [% SET hold_itemtype = h.object.item.effective_itemtype || h.itemtype %]
1353
                                            [% INCLUDE holds_table.inc biblio_id=biblioloo.biblionumber total_holds=biblioloo.total_holds split_data="any" %]
1369
                                        [% itemtypes.push( hold_itemtype ) %]
1354
                                        </div>
1370
                                    [% END %]
1371
                                    [% itemtypes = itemtypes.unique %]
1372
                                    [% IF ( itemtypes.empty ) %]
1373
                                        <div class="alert alert-info"> There are no holds on this title. </div>
1374
                                    [% ELSE %]
1355
                                    [% ELSE %]
1375
1356
                                        [% FOREACH i IN biblioloo.hold_itemtypes %]
1376
                                        [% FOREACH i IN itemtypes.sort %]
1377
                                            [% SET holds_by_itemtype = [] %]
1378
                                            [% FOREACH h IN biblioloo.reserveloop %]
1379
                                                [% SET hold_itemtype = h.object.item.effective_itemtype || h.itemtype %]
1380
                                                [% IF hold_itemtype == i %]
1381
                                                    [% holds_by_itemtype.push( h ) %]
1382
                                                [% END %]
1383
                                            [% END %]
1384
1385
                                            <div class="holds_by_itemtype">
1357
                                            <div class="holds_by_itemtype">
1386
                                                [% IF i %]
1358
                                                [% IF i && i != 'any' %]
1387
                                                    <h4>[% ItemTypes.GetDescription( i ) | html %]</h4>
1359
                                                    <h4>[% ItemTypes.GetDescription( i ) | html %]</h4>
1388
                                                [% ELSE %]
1360
                                                [% ELSE %]
1389
                                                    <h4>Any item type</h4>
1361
                                                    <h4>Any item type</h4>
1390
                                                [% END %]
1362
                                                [% END %]
1391
                                                [% INCLUDE holds_table.inc holds=holds_by_itemtype %]
1363
                                                [% INCLUDE holds_table.inc biblio_id=biblioloo.biblionumber total_holds=biblioloo.total_holds split_data=i %]
1392
                                            </div>
1364
                                            </div>
1393
                                        [% END # /FOREACH i %]
1365
                                        [% END %]
1394
                                    [% END # /IF ( itemtypes.empty ) %]
1366
                                    [% END # /IF hold_split.empty %]
1395
                                [% ELSIF Koha.Preference('HoldsSplitQueue') == 'branch_itemtype' %]
1367
                                [% ELSIF Koha.Preference('HoldsSplitQueue') == 'branch_itemtype' %]
1396
                                    [% SET branchcodes = [] %]
1397
1368
1398
                                    [% FOREACH h IN biblioloo.reserveloop %]
1369
                                    [% FOREACH b IN biblioloo.hold_branches %]
1399
                                        [% branchcodes.push( h.branchcode ) %]
1370
                                        <div class="holds_by_library">
1400
                                    [% END %]
1371
                                            <h4>[% Branches.GetName( b ) | html %]</h4>
1401
                                    [% branchcodes = branchcodes.unique %]
1372
                                            [% FOREACH i IN biblioloo.hold_itemtypes %]
1402
                                    [% IF ( branchcodes.empty ) %]
1373
                                                <div class="holds_by_itemtype">
1403
                                        <div class="alert alert-info"> There are no holds on this title. </div>
1374
                                                    [% IF i && i != 'any' %]
1404
                                    [% ELSE %]
1375
                                                        <h4>[% ItemTypes.GetDescription( i ) | html %]</h4>
1405
1376
                                                    [% ELSE %]
1406
                                        [% FOREACH b IN branchcodes.sort %]
1377
                                                        <h4>Any item type</h4>
1407
                                            <div class="holds_by_library">
1408
                                                <h4 class="library_holds">[% Branches.GetName( b ) | html %]</h4>
1409
                                                [% SET holds_by_branch = [] %]
1410
                                                [% FOREACH h IN biblioloo.reserveloop %]
1411
                                                    [% IF h.branchcode == b %]
1412
                                                        [% holds_by_branch.push( h ) %]
1413
                                                    [% END %]
1378
                                                    [% END %]
1414
                                                [% END %]
1379
                                                    [% SET split_data = b _ "_" _ i %]
1415
1380
                                                    [% INCLUDE holds_table.inc biblio_id=biblioloo.biblionumber total_holds=biblioloo.total_holds split_data=split_data %]
1416
                                                [% SET itemtypes = [] %]
1381
                                                </div>
1417
                                                [% FOREACH h IN holds_by_branch %]
1382
                                            [% END %]
1418
                                                    [% SET hold_itemtype = h.object.item.effective_itemtype || h.itemtype %]
1383
                                        </div>
1419
                                                    [% itemtypes.push( hold_itemtype ) %]
1420
                                                [% END %]
1421
                                                [% itemtypes = itemtypes.unique %]
1422
1423
                                                [% FOREACH i IN itemtypes.sort %]
1424
                                                    <div class="holds_by_itemtype">
1425
                                                        <h5 class="itemtype_holds">
1426
                                                            [% IF i %]
1427
                                                                [% ItemTypes.GetDescription( i ) | html %]
1428
                                                            [% ELSE %]
1429
                                                                <span>Any item type</span>
1430
                                                            [% END %]
1431
                                                        </h5>
1432
1433
                                                        [% SET holds_by_itemtype = [] %]
1434
                                                        [% FOREACH h IN holds_by_branch %]
1435
                                                            [% SET hold_itemtype = h.object.item.effective_itemtype || h.itemtype %]
1436
                                                            [% IF hold_itemtype == i %]
1437
                                                                [% holds_by_itemtype.push( h ) %]
1438
                                                            [% END %]
1439
                                                        [% END %]
1440
                                                        [% INCLUDE holds_table.inc holds=holds_by_itemtype %]
1441
                                                    </div>
1442
                                                    <!-- /.holds_by_itemtype -->
1443
                                                [% END %]
1444
                                            </div>
1445
                                            <!-- /.holds_by_library -->
1446
                                        [% END # /FOREACH b %]
1447
                                    [% END # /IF ( branchcodes.empty ) %]
1448
                                [% ELSE %]
1449
1450
                                    [% IF ( biblioloo.reserveloop.size ) %]
1451
                                        [% INCLUDE holds_table.inc holds=biblioloo.reserveloop %]
1452
                                    [% ELSE %]
1453
                                        <div class="alert alert-info"> There are no holds on this title. </div>
1454
                                    [% END %]
1384
                                    [% END %]
1385
                                [% ELSE %]
1386
                                    [% INCLUDE holds_table.inc biblio_id=biblioloo.biblionumber total_holds=biblioloo.total_holds split_data="any" %]
1455
                                [% END # /IF HoldsSplitQueue %]
1387
                                [% END # /IF HoldsSplitQueue %]
1456
                            </div>
1388
                            </div>
1457
                            <!-- /hold_title -->
1389
                            <!-- /hold_title -->
1458
                        [% END # /IF biblioloo.reserveloop %]
1390
                        [% ELSE %]
1391
                            <div class="note"> There are no holds on this title. </div>
1392
                        [% END # /IF ( biblioloo.total_holds ) %]
1459
                    [% END # FOREACH biblioloo %]
1393
                    [% END # FOREACH biblioloo %]
1460
                </div>
1394
                </div>
1461
            </form>
1395
            </form>
Lines 1570-1575 Link Here
1570
    [% INCLUDE 'datatables.inc' %]
1504
    [% INCLUDE 'datatables.inc' %]
1571
    [% INCLUDE 'calendar.inc' %]
1505
    [% INCLUDE 'calendar.inc' %]
1572
    [% INCLUDE 'select2.inc' %]
1506
    [% INCLUDE 'select2.inc' %]
1507
    <script>
1508
        hold_table_settings = [% TablesSettings.GetTableSettings( 'circ', 'holds', 'patron_holds_table', 'json' ) | $raw %];
1509
    </script>
1573
    [% Asset.js("js/holds.js") | $raw %]
1510
    [% Asset.js("js/holds.js") | $raw %]
1574
    [% Asset.js("js/hold-group.js") | $raw %]
1511
    [% Asset.js("js/hold-group.js") | $raw %]
1575
1512
Lines 1578-1594 Link Here
1578
        [% SET url_biblio_params = url_biblio_params _ "&amp;multi_hold=1" %]
1515
        [% SET url_biblio_params = url_biblio_params _ "&amp;multi_hold=1" %]
1579
    [% END %]
1516
    [% END %]
1580
    <script>
1517
    <script>
1581
        $(document).ready(function () {
1582
            hold_table_settings = [% TablesSettings.GetTableSettings( 'circ', 'holds', 'patron_holds_table', 'json' ) | $raw %];
1583
            $("#patron_holds_table").kohaTable(
1584
                {
1585
                    paging: false,
1586
                    bKohaColumnsUseNames: true,
1587
                },
1588
                hold_table_settings
1589
            );
1590
        });
1591
        var biblionumbers = [[% biblionumbers.join(', ') | $raw %]];
1518
        var biblionumbers = [[% biblionumbers.join(', ') | $raw %]];
1519
        var hold_branches = {[% FOREACH biblio_info IN biblioloop %] [% biblio_info.biblionumber | html %]: ["[% biblio_info.hold_branches.join('", "') | $raw %]"], [% END %]};
1520
        var hold_itemtypes = {[% FOREACH biblio_info IN biblioloop %] [% biblio_info.biblionumber | html %]: ["[% biblio_info.hold_itemtypes.join('", "') | $raw %]"], [% END %]};
1521
        var HoldsSplitQueue = "[% Koha.Preference('HoldsSplitQueue') | html %]";
1522
        var HoldsSplitQueueNumbering = "[% Koha.Preference('HoldsSplitQueueNumbering') | html %]";
1523
        var SuspendHoldsIntranet = [% ( Koha.Preference('SuspendHoldsIntranet') ) ? 1 : 0 | html %];
1524
        var AutoResumeSuspendedHolds = [% ( Koha.Preference('AutoResumeSuspendedHolds') ) ? 1 : 0 | html %];
1525
        var AllowHoldDateInFuture = [% ( Koha.Preference('AllowHoldDateInFuture') ) ? 1 : 0 | html %];
1526
        var HidePatronName = [% ( Koha.Preference('HidePatronName') ) ? 1 : 0 | html %];
1527
        var CAN_user_reserveforothers_modify_holds_priority = [%CAN_user_reserveforothers_modify_holds_priority ? 1 : 0 | html %];
1592
        var borrowernumber = "[% patron.borrowernumber | $raw %]";
1528
        var borrowernumber = "[% patron.borrowernumber | $raw %]";
1593
        var patron_homebranch = "[% To.json( Branches.GetName( patron.branchcode ) ) | $raw %]";
1529
        var patron_homebranch = "[% To.json( Branches.GetName( patron.branchcode ) ) | $raw %]";
1594
        var override_items = {[% FOREACH biblio_info IN biblioloop %][% FOREACH itemloo IN biblio_info.itemloop %][% IF ( itemloo.override ) %]
1530
        var override_items = {[% FOREACH biblio_info IN biblioloop %][% FOREACH itemloo IN biblio_info.itemloop %][% IF ( itemloo.override ) %]
Lines 1616-1621 Link Here
1616
        $.fn.select2.defaults.set("dropdownAutoWidth", true );
1552
        $.fn.select2.defaults.set("dropdownAutoWidth", true );
1617
1553
1618
        $(document).ready(function() {
1554
        $(document).ready(function() {
1555
            biblionumbers.forEach(function(biblionumber) {
1556
                let branches = hold_branches[biblionumber];
1557
                let itemtypes = hold_itemtypes[biblionumber];
1558
                switch (HoldsSplitQueue) {
1559
                    case 'branch':
1560
                        branches.forEach(function(branch) {
1561
                            load_patron_holds_table(biblionumber, {name: HoldsSplitQueue, value: branch});
1562
                        });
1563
                        break;
1564
                    case 'itemtype':
1565
                        itemtypes.forEach(function(itemtype) {
1566
                            load_patron_holds_table(biblionumber, {name: HoldsSplitQueue, value: itemtype});
1567
                        });
1568
                        break;
1569
                    case 'branch_itemtype':
1570
                        branches.forEach(function(branch) {
1571
                            itemtypes.forEach(function(itemtype) {
1572
                                load_patron_holds_table(biblionumber, {name: HoldsSplitQueue, value: branch + '_' + itemtype});
1573
                            });
1574
                        });
1575
                        break;
1576
                    default:
1577
                        load_patron_holds_table(biblionumber, {name: 'any', value: 'any'});
1578
                }
1579
            });
1619
            $('#cancellation-reason-div').hide();
1580
            $('#cancellation-reason-div').hide();
1620
            $('.rank-request').on('change', function() {
1581
            $('.rank-request').on('change', function() {
1621
                if ( $(".rank-request option:selected[value='del']").length ) {
1582
                if ( $(".rank-request option:selected[value='del']").length ) {
Lines 1976-2041 Link Here
1976
                });
1937
                });
1977
            [% END %]
1938
            [% END %]
1978
1939
1979
            $(".hold-arrow").click(function(e) {
1940
            if(!localStorage.selectedHolds  || document.referrer.replace(/\?.*/, '') !== document.location.origin+document.location.pathname) {
1980
                e.preventDefault();
1941
                localStorage.selectedHolds = [];
1981
                let arrowForm = $("#hold-actions-form").attr({
1942
            }
1982
                    action: 'request.pl',
1943
1983
                    method: 'post'
1984
                });
1985
                let arrow_op = $("<input />").attr({
1986
                    name: 'op',
1987
                    type: 'hidden',
1988
                    value: $(this).data('op')
1989
                });
1990
                let arrow_where = $("<input />").attr({
1991
                    name: 'where',
1992
                    type: 'hidden',
1993
                    value: $(this).data('where')
1994
                });
1995
                let arrow_fp = $("<input />").attr({
1996
                    name: 'first_priority',
1997
                    type: 'hidden',
1998
                    value: $(this).data('first_priority')
1999
                });
2000
                let arrow_lp = $("<input />").attr({
2001
                    name: 'last_priority',
2002
                    type: 'hidden',
2003
                    value: $(this).data('last_priority')
2004
                });
2005
                let arrow_pp = $("<input />").attr({
2006
                    name: 'prev_priority',
2007
                    type: 'hidden',
2008
                    value: $(this).data('prev_priority')
2009
                });
2010
                let arrow_np = $("<input />").attr({
2011
                    name: 'next_priority',
2012
                    type: 'hidden',
2013
                    value: $(this).data('next_priority')
2014
                });
2015
                let arrow_bn = $("<input />").attr({
2016
                    name: 'borrowernumber',
2017
                    type: 'hidden',
2018
                    value: $(this).data('borrowernumber')
2019
                });
2020
                let arrow_bb = $("<input />").attr({
2021
                    name: 'biblionumber',
2022
                    type: 'hidden',
2023
                    value: $(this).data('biblionumber')
2024
                });
2025
                let arrow_ri = $("<input />").attr({
2026
                    name: 'reserve_id',
2027
                    type: 'hidden',
2028
                    value: $(this).data('reserve_id')
2029
                });
2030
                let arrow_date = $("<input />").attr({
2031
                    name: 'date',
2032
                    type: 'hidden',
2033
                    value: $(this).data('date')
2034
                });
2035
                arrowForm.append(arrow_op,arrow_where,arrow_fp,arrow_lp,arrow_pp,arrow_np,arrow_bn,arrow_bb,arrow_ri,arrow_date);
2036
                $("#hold-actions-form").submit();
2037
                return true;
2038
            })
2039
        });
1944
        });
2040
    </script>
1945
    </script>
2041
    <script>
1946
    <script>
Lines 2051-2063 Link Here
2051
            });
1956
            });
2052
        </script>
1957
        </script>
2053
    [% END %]
1958
    [% END %]
2054
    <script>
2055
        $(".printholdslip").click(function () {
2056
            var reserve_id = $(this).attr("data-reserve_id");
2057
            window.open("/cgi-bin/koha/circ/hold-transfer-slip.pl?reserve_id=" + reserve_id);
2058
            return false;
2059
        });
2060
    </script>
2061
[% END %]
1959
[% END %]
2062
1960
2063
[% INCLUDE 'intranet-bottom.inc' %]
1961
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/koha-tmpl/intranet-tmpl/prog/js/datatables.js (+3 lines)
Lines 1455-1460 function update_search_description( Link Here
1455
                    emptyTable: options.emptyTable
1455
                    emptyTable: options.emptyTable
1456
                        ? options.emptyTable
1456
                        ? options.emptyTable
1457
                        : __("No data available in table"),
1457
                        : __("No data available in table"),
1458
                    infoFiltered: options.infoFiltered
1459
                        ? options.infoFiltered
1460
                        : __("(filtered from _MAX_ total entries)"),
1458
                },
1461
                },
1459
            },
1462
            },
1460
            options
1463
            options
(-)a/koha-tmpl/intranet-tmpl/prog/js/holds.js (-134 / +1217 lines)
Lines 791-803 $(document).ready(function () { Link Here
791
        }
791
        }
792
    });
792
    });
793
793
794
    if (!patron_page) {
794
    // if (!patron_page) {
795
        $(".holds_table .select_hold_all").each(function () {
795
    //     $(".holds_table .select_hold_all").each(function () {
796
            var table = $(this).parents(".holds_table");
796
    //         var table = $(this).parents(".holds_table");
797
            var count = $(".select_hold:not(:checked)", table).length;
797
    //         var count = $(".select_hold:not(:checked)", table).length;
798
            $(".select_hold_all", table).prop("checked", !count);
798
    //         $(".select_hold_all", table).prop("checked", !count);
799
        });
799
    //     });
800
    }
800
    // }
801
801
802
    function updateSelectedHoldsButtonCounters() {
802
    function updateSelectedHoldsButtonCounters() {
803
        $(".move_selected_holds").html(
803
        $(".move_selected_holds").html(
Lines 808-827 $(document).ready(function () { Link Here
808
        $(".selected_holds_count").html(
808
        $(".selected_holds_count").html(
809
            $(".holds_table .select_hold:checked").length
809
            $(".holds_table .select_hold:checked").length
810
        );
810
        );
811
        if (patron_page) {
811
        var selectedHolds = $(".holds_table .select_hold:checked");
812
            var selectedHolds = $(".holds_table .select_hold:checked");
812
        var hasSelectedHolds = selectedHolds.length > 0;
813
            var hasSelectedHolds = selectedHolds.length > 0;
813
        var hasMultipleSelectedHolds = selectedHolds.length >= 2;
814
            var hasMultipleSelectedHolds = selectedHolds.length >= 2;
815
814
816
            $(".cancel_selected_holds, .suspend_selected_holds").prop(
815
        $(".cancel_selected_holds, .suspend_selected_holds").prop(
817
                "disabled",
816
            "disabled",
818
                !hasSelectedHolds
817
            !hasSelectedHolds
819
            );
818
        );
820
            $(".group_selected_holds").prop(
819
        $(".group_selected_holds").prop("disabled", !hasMultipleSelectedHolds);
821
                "disabled",
822
                !hasMultipleSelectedHolds
823
            );
824
        }
825
    }
820
    }
826
821
827
    function updateMoveButtons(table) {
822
    function updateMoveButtons(table) {
Lines 841-936 $(document).ready(function () { Link Here
841
        $(".move_selected_holds").prop("disabled", !checked_count);
836
        $(".move_selected_holds").prop("disabled", !checked_count);
842
    }
837
    }
843
838
844
    updateSelectedHoldsButtonCounters();
839
    if (holds_table_patron_page()) {
840
        updateSelectedHoldsButtonCounters();
845
841
846
    $(".holds_table .select_hold_all").click(function () {
842
        $(".holds_table .select_hold_all").click(function () {
847
        var table;
843
            var table = $(".holds_table:not(.fixedHeader-floating)");
848
        if (!patron_page) {
849
            table = $(this).parents(".holds_table");
850
        } else {
851
            table = $(".holds_table:not(.fixedHeader-floating)");
852
        }
853
844
854
        var checked_count = $(".select_hold:checked", table).length;
845
            var checked_count = $(".select_hold:checked", table).length;
855
        $(".select_hold", table).prop("checked", !checked_count);
846
            $(".select_hold", table).prop("checked", !checked_count);
856
        $(this).prop("checked", !checked_count);
847
            $(this).prop("checked", !checked_count);
857
848
858
        updateMoveButtons(table);
849
            updateMoveButtons(table);
859
850
860
        updateSelectedHoldsButtonCounters();
851
            updateSelectedHoldsButtonCounters();
861
        $("#cancel_hold_alert").html(
852
            $("#cancel_hold_alert").html(
862
            MSG_CANCEL_ALERT.format(
853
                MSG_CANCEL_ALERT.format(
863
                $(".holds_table .select_hold:checked").length
854
                    $(".holds_table .select_hold:checked").length
864
            )
865
        );
866
        $("#cancel_hold_alert").show();
867
        localStorage.selectedHolds =
868
            "[" +
869
            $(".holds_table .select_hold:checked")
870
                .toArray()
871
                .map(el =>
872
                    JSON.stringify({
873
                        hold: $(el).data("id"),
874
                        borrowernumber: $(el).data("borrowernumber"),
875
                        biblionumber: $(el).data("biblionumber"),
876
                    })
877
                )
855
                )
878
                .join(",") +
856
            );
879
            "]";
857
            $("#cancel_hold_alert").show();
880
    });
858
            localStorage.selectedHolds =
859
                "[" +
860
                $(".holds_table .select_hold:checked")
861
                    .toArray()
862
                    .map(el =>
863
                        JSON.stringify({
864
                            hold: $(el).data("id"),
865
                            borrowernumber: $(el).data("borrowernumber"),
866
                            biblionumber: $(el).data("biblionumber"),
867
                        })
868
                    )
869
                    .join(",") +
870
                "]";
871
        });
881
872
882
    $(".holds_table").on("click", ".select_hold", function () {
873
        $(".holds_table").on("click", ".select_hold", function () {
883
        var table = $(this).parents(".holds_table");
874
            var table = $(this).parents(".holds_table");
884
        var count = $(".select_hold:not(:checked)", table).length;
875
            var count = $(".select_hold:not(:checked)", table).length;
885
        $(".select_hold_all", table).prop("checked", !count);
876
            $(".select_hold_all", table).prop("checked", !count);
886
877
887
        updateMoveButtons(table);
878
            updateMoveButtons(table);
888
879
889
        updateSelectedHoldsButtonCounters();
880
            updateSelectedHoldsButtonCounters();
890
        $("#cancel_hold_alert").html(
881
            $("#cancel_hold_alert").html(
891
            MSG_CANCEL_ALERT.format(
882
                MSG_CANCEL_ALERT.format(
892
                $(".holds_table .select_hold:checked").length
883
                    $(".holds_table .select_hold:checked").length
893
            )
894
        );
895
        $("#cancel_hold_alert").show();
896
        localStorage.selectedHolds =
897
            "[" +
898
            $(".holds_table .select_hold:checked")
899
                .toArray()
900
                .map(el =>
901
                    JSON.stringify({
902
                        hold: $(el).data("id"),
903
                        borrowernumber: $(el).data("borrowernumber"),
904
                        biblionumber: $(el).data("biblionumber"),
905
                    })
906
                )
884
                )
907
                .join(",") +
885
            );
908
            "]";
886
            $("#cancel_hold_alert").show();
909
    });
887
            localStorage.selectedHolds =
910
888
                "[" +
911
    $(".cancel_selected_holds").click(function (e) {
889
                $(".holds_table .select_hold:checked")
912
        e.preventDefault();
913
        if ($(".holds_table .select_hold:checked").length) {
914
            $("#cancel_modal_form #inputs").empty();
915
            if (!patron_page) {
916
                biblionumbers.forEach(function (biblionumber) {
917
                    $("#cancel_modal_form #inputs").append(
918
                        '<input type="hidden" name="biblionumber" value="' +
919
                            biblionumber +
920
                            '">'
921
                    );
922
                });
923
                $("#cancel_modal_form #inputs").append(
924
                    '<input type="hidden" name="op" value="cud-cancel_bulk">'
925
                );
926
                let hold_ids = $(".holds_table .select_hold:checked")
927
                    .toArray()
890
                    .toArray()
928
                    .map(el => $(el).data("id"))
891
                    .map(el =>
929
                    .join(",");
892
                        JSON.stringify({
930
                $("#cancel_modal_form #inputs").append(
893
                            hold: $(el).data("id"),
931
                    '<input type="hidden" name="ids" value="' + hold_ids + '">'
894
                            borrowernumber: $(el).data("borrowernumber"),
932
                );
895
                            biblionumber: $(el).data("biblionumber"),
933
            } else {
896
                        })
897
                    )
898
                    .join(",") +
899
                "]";
900
        });
901
902
        $(".cancel_selected_holds").click(function (e) {
903
            e.preventDefault();
904
            if ($(".holds_table .select_hold:checked").length) {
905
                $("#cancel_modal_form #inputs").empty();
934
                $("#cancel_modal_form #inputs").append(
906
                $("#cancel_modal_form #inputs").append(
935
                    '<input type="hidden" name="op" value="cud-cancelall">'
907
                    '<input type="hidden" name="op" value="cud-cancelall">'
936
                );
908
                );
Lines 950-963 $(document).ready(function () { Link Here
950
                JSON.parse(hold_data).forEach(function (hold) {
922
                JSON.parse(hold_data).forEach(function (hold) {
951
                    _append_patron_page_cancel_hold_modal_data(hold);
923
                    _append_patron_page_cancel_hold_modal_data(hold);
952
                });
924
                });
925
                delete localStorage.selectedHolds;
926
                $("#cancelModal").modal("show");
953
            }
927
            }
954
928
            return false;
955
            delete localStorage.selectedHolds;
929
        });
956
            $("#cancelModal").modal("show");
930
    }
957
        }
958
        return false;
959
    });
960
961
    $("#itemSearchForm").on("submit", function (event) {
931
    $("#itemSearchForm").on("submit", function (event) {
962
        event.preventDefault();
932
        event.preventDefault();
963
        $("#move_hold_item_confirm").prop("disabled", true);
933
        $("#move_hold_item_confirm").prop("disabled", true);
Lines 1076-1093 $(document).ready(function () { Link Here
1076
            $("#itemResultMessage").empty();
1046
            $("#itemResultMessage").empty();
1077
            $("#move_hold_item_selection table tbody").empty();
1047
            $("#move_hold_item_selection table tbody").empty();
1078
            $("#moveHoldItemModal").modal("show");
1048
            $("#moveHoldItemModal").modal("show");
1079
            $(".select_hold:checked").each(function () {
1049
            const selectedHolds =
1080
                let reserve_id = $(this).data("id");
1050
                JSON.parse(localStorage.selectedHolds) ||
1081
                let reserve_biblionumber = $(this).data("biblionumber");
1051
                $(".select_hold:checked");
1082
                let reserve_itemnumber = $(this).data("itemnumber");
1052
            $(selectedHolds).each(function () {
1083
                let item_level_hold = $(this).data("item_level_hold");
1053
                let reserve_id = this.hold || $(this).data("id");
1084
                let item_waiting = $(this).data("waiting");
1054
                let reserve_biblionumber =
1085
                let item_intransit = $(this).data("intransit");
1055
                    this.biblionumber || $(this).data("biblionumber");
1086
                let error_message = $(this).data("item_level_hold")
1056
                let reserve_itemnumber =
1087
                    ? ""
1057
                    this.itemnumber || $(this).data("itemnumber");
1088
                    : __(
1058
                let item_level_hold =
1089
                          "Cannot move a waiting, in transit, or record level hold"
1059
                    this.item_level_hold || $(this).data("item_level_hold");
1090
                      );
1060
                let item_waiting = this.waiting || $(this).data("waiting");
1061
                let item_intransit =
1062
                    this.intransit || $(this).data("intransit");
1063
                let error_message =
1064
                    this.item_level_hold || $(this).data("item_level_hold")
1065
                        ? ""
1066
                        : __(
1067
                              "Cannot move a waiting, in transit, or record level hold"
1068
                          );
1091
                let found_status = $(this).data("found");
1069
                let found_status = $(this).data("found");
1092
                if (item_level_hold && (!item_waiting || !item_intransit)) {
1070
                if (item_level_hold && (!item_waiting || !item_intransit)) {
1093
                    $("#move_hold_item_selection table").append(
1071
                    $("#move_hold_item_selection table").append(
Lines 1105-1127 $(document).ready(function () { Link Here
1105
    $(".move_hold_biblio").click(function (e) {
1083
    $(".move_hold_biblio").click(function (e) {
1106
        e.preventDefault();
1084
        e.preventDefault();
1107
        $("#move_hold_biblio_confirm").prop("disabled", true);
1085
        $("#move_hold_biblio_confirm").prop("disabled", true);
1108
        if ($(".holds_table .select_hold:checked").length) {
1086
        const selectedHolds =
1087
            JSON.parse(localStorage.selectedHolds || "[]") ||
1088
            $(".select_hold:checked");
1089
        if (selectedHolds.length) {
1109
            $("#biblioResultMessage").empty();
1090
            $("#biblioResultMessage").empty();
1110
            $("#move_hold_biblio_selection table tbody").empty();
1091
            $("#move_hold_biblio_selection table tbody").empty();
1111
            $("#moveHoldBiblioModal").modal("show");
1092
            $("#moveHoldBiblioModal").modal("show");
1112
            $(".select_hold:checked").each(function () {
1093
            $(selectedHolds).each(function () {
1113
                let reserve_id = $(this).data("id");
1094
                let reserve_id = this.hold || $(this).data("id");
1114
                let reserve_biblionumber = $(this).data("biblionumber");
1095
                let reserve_biblionumber =
1115
                let reserve_itemnumber = $(this).data("itemnumber");
1096
                    this.biblionumber || $(this).data("biblionumber");
1116
                let item_level_hold = $(this).data("item_level_hold");
1097
                let reserve_itemnumber =
1117
                let item_status = $(this).data("status");
1098
                    this.itemnumber || $(this).data("itemnumber");
1118
                let item_waiting = $(this).data("waiting");
1099
                let item_level_hold =
1119
                let item_intransit = $(this).data("intransit");
1100
                    this.item_level_hold || $(this).data("item_level_hold");
1120
                let error_message = $(this).data("item_level_hold")
1101
                let item_status = this.status || $(this).data("status");
1121
                    ? __(
1102
                let item_waiting = this.waiting || $(this).data("waiting");
1122
                          "Cannot move a waiting, in transit, or item level hold"
1103
                let item_intransit =
1123
                      )
1104
                    this.intransit || $(this).data("intransit");
1124
                    : "";
1105
                let error_message =
1106
                    this.item_level_hold || $(this).data("item_level_hold")
1107
                        ? __(
1108
                              "Cannot move a waiting, in transit, or item level hold"
1109
                          )
1110
                        : "";
1125
                let found_status = $(this).data("found");
1111
                let found_status = $(this).data("found");
1126
                if (!item_level_hold && (!item_waiting || !item_intransit)) {
1112
                if (!item_level_hold && (!item_waiting || !item_intransit)) {
1127
                    $("#move_hold_biblio_selection table").append(
1113
                    $("#move_hold_biblio_selection table").append(
Lines 1230-1236 $(document).ready(function () { Link Here
1230
    $("#cancelModal").on("hidden.bs.modal", function () {
1216
    $("#cancelModal").on("hidden.bs.modal", function () {
1231
        $("#cancelModal .modal-body .alert-danger").remove();
1217
        $("#cancelModal .modal-body .alert-danger").remove();
1232
        $("#cancelModalConfirmBtn").prop("disabled", false);
1218
        $("#cancelModalConfirmBtn").prop("disabled", false);
1233
        holdsTable.api().ajax.reload();
1219
        if (holdsTable) {
1220
            holdsTable.api().ajax.reload();
1221
        }
1234
    });
1222
    });
1235
1223
1236
    $("#group-modal-submit").click(function (e) {
1224
    $("#group-modal-submit").click(function (e) {
Lines 1303-1305 $(document).ready(function () { Link Here
1303
        );
1291
        );
1304
    }
1292
    }
1305
});
1293
});
1294
1295
async function load_patron_holds_table(biblio_id, split_data) {
1296
    const { name: split_name, value: split_value } = split_data;
1297
    let table_class = `patron_holds_table_${biblio_id}_${split_value}`;
1298
    const table_id = `#` + table_class;
1299
    let url = `/api/v1/holds/?q={"me.biblio_id":${biblio_id}`;
1300
1301
    if (split_name === "branch" && split_value !== "any") {
1302
        url += `, "me.pickup_library_id":"${split_value}"`;
1303
    } else if (split_name === "itemtype" && split_value !== "any") {
1304
        url += `, "me.itemtype":"${split_value}"`;
1305
    } else if (split_name === "branch_itemtype") {
1306
        const [branch, itemtype] = split_value.split("_");
1307
        url +=
1308
            itemtype === "any"
1309
                ? `, "me.pickup_library_id":"${branch}"`
1310
                : `, "me.pickup_library_id":"${branch}", "me.itemtype":"${itemtype}"`;
1311
    }
1312
1313
    url += "}";
1314
    const totalHolds = $(table_id).data("total-holds");
1315
    const totalHoldsSelect = parseInt(totalHolds) + 1;
1316
    var holdsQueueTable = $(table_id).kohaTable(
1317
        {
1318
            language: {
1319
                infoFiltered: "",
1320
            },
1321
            ajax: {
1322
                url: url,
1323
            },
1324
            embed: ["patron", "item", "item_group", "item_level_holds"],
1325
            columnDefs: [
1326
                {
1327
                    targets: [2, 3],
1328
                    className: "dt-body-nowrap",
1329
                },
1330
                {
1331
                    targets: [3, 9],
1332
                    visible: CAN_user_reserveforothers_modify_holds_priority
1333
                        ? true
1334
                        : false,
1335
                },
1336
            ],
1337
            columns: [
1338
                {
1339
                    data: "hold_id",
1340
                    orderable: false,
1341
                    searchable: false,
1342
                    render: function (data, type, row, meta) {
1343
                        return (
1344
                            '<input type="checkbox" class="select_hold ' +
1345
                            table_class +
1346
                            '" data-id="' +
1347
                            data +
1348
                            '" data-borrowernumber="' +
1349
                            row.patron_id +
1350
                            '" data-biblionumber="' +
1351
                            biblio_id +
1352
                            '" data-itemnumber="' +
1353
                            row.item_id +
1354
                            '" data-hold-group-id="' +
1355
                            row.hold_group_id +
1356
                            '" data-item_level_hold="' +
1357
                            row.item_level_holds +
1358
                            '" data-waiting="' +
1359
                            (row.status === "W" ? "1" : "") +
1360
                            '" data-intransit="' +
1361
                            (row.status === "T" ? "1" : "") +
1362
                            '" data-status="' +
1363
                            (row.status ? row.status : "") +
1364
                            '"/>'
1365
                        );
1366
                    },
1367
                },
1368
                {
1369
                    data: "priority",
1370
                    orderable: true,
1371
                    searchable: false,
1372
                    render: function (data, type, row, meta) {
1373
                        let select =
1374
                            '<select name="rank-request" class="rank-request ' +
1375
                            table_class +
1376
                            '" data-id="' +
1377
                            row.hold_id;
1378
                        if (
1379
                            CAN_user_reserveforothers_modify_holds_priority &&
1380
                            split_name == "any"
1381
                        ) {
1382
                            for (var i = 0; i < totalHoldsSelect; i++) {
1383
                                let selected;
1384
                                let value;
1385
                                let desc;
1386
                                if (data == i && row.status == "T") {
1387
                                    select += '" disabled="disabled">';
1388
                                    selected = " selected='selected' ";
1389
                                    value = "T";
1390
                                    desc = "In transit";
1391
                                } else if (data == i && row.status == "P") {
1392
                                    select += '" disabled="disabled">';
1393
                                    selected = " selected='selected' ";
1394
                                    value = "P";
1395
                                    desc = "In processing";
1396
                                } else if (data == i && row.status == "W") {
1397
                                    select += '" disabled="disabled">';
1398
                                    selected = " selected='selected' ";
1399
                                    value = "W";
1400
                                    desc = "Waiting";
1401
                                } else if (data == i && !row.status) {
1402
                                    select += '">';
1403
                                    selected = " selected='selected' ";
1404
                                    value = data;
1405
                                    desc = data;
1406
                                } else {
1407
                                    if (i != 0) {
1408
                                        select += '">';
1409
                                        value = i;
1410
                                        desc = i;
1411
                                    } else {
1412
                                        select += '">';
1413
                                    }
1414
                                }
1415
                                if (value) {
1416
                                    select +=
1417
                                        '<option value="' +
1418
                                        value +
1419
                                        '"' +
1420
                                        selected +
1421
                                        ">" +
1422
                                        desc +
1423
                                        "</option>";
1424
                                }
1425
                            }
1426
                        } else {
1427
                            if (row.status == "T") {
1428
                                select +=
1429
                                    '" disabled="disabled"><option value="T" selected="selected">In transit</option></select>';
1430
                            } else if (row.status == "P") {
1431
                                select +=
1432
                                    '" disabled="disabled"><option value="P" selected="selected">In processing</option></select>';
1433
                            } else if (row.status == "W") {
1434
                                select +=
1435
                                    '" disabled="disabled"><option value="W" selected="selected">Waiting</option></select>';
1436
                            } else {
1437
                                if (
1438
                                    HoldsSplitQueue !== "nothing" &&
1439
                                    HoldsSplitQueueNumbering === "virtual"
1440
                                ) {
1441
                                    let virtualPriority =
1442
                                        meta.settings._iDisplayStart +
1443
                                        meta.row +
1444
                                        1;
1445
                                    select +=
1446
                                        '" disabled="disabled"><option value="' +
1447
                                        data +
1448
                                        '" selected="selected">' +
1449
                                        virtualPriority +
1450
                                        "</option></select>";
1451
                                } else {
1452
                                    select +=
1453
                                        '" disabled="disabled"><option value="' +
1454
                                        data +
1455
                                        '" selected="selected">' +
1456
                                        data +
1457
                                        "</option></select>";
1458
                                }
1459
                            }
1460
                        }
1461
                        select += "</select>";
1462
                        return select;
1463
                    },
1464
                },
1465
                {
1466
                    data: "",
1467
                    orderable: false,
1468
                    searchable: false,
1469
                    render: function (data, type, row, meta) {
1470
                        if (row.status) {
1471
                            return null;
1472
                        }
1473
                        let buttons =
1474
                            '<a class="hold-arrow move-hold ' +
1475
                            table_class +
1476
                            '" title="Move hold up" href="#" data-move-hold="up" data-priority="' +
1477
                            row.priority +
1478
                            '" reserve_id="' +
1479
                            row.hold_id +
1480
                            '"><i class="fa fa-lg icon-move-hold-up" aria-hidden="true"></i></a>';
1481
                        buttons +=
1482
                            '<a class="hold-arrow move-hold ' +
1483
                            table_class +
1484
                            '" title="Move hold to top" href="#" data-move-hold="top" data-priority="' +
1485
                            row.priority +
1486
                            '" reserve_id="' +
1487
                            row.hold_id +
1488
                            '"><i class="fa fa-lg icon-move-hold-top" aria-hidden="true"></i></a>';
1489
                        buttons +=
1490
                            '<a class="hold-arrow move-hold ' +
1491
                            table_class +
1492
                            '" title="Move hold to bottom" href="#" data-move-hold="bottom" data-priority="' +
1493
                            row.priority +
1494
                            '" reserve_id="' +
1495
                            row.hold_id +
1496
                            '"><i class="fa fa-lg icon-move-hold-bottom" aria-hidden="true"></i></a>';
1497
                        buttons +=
1498
                            '<a class="hold-arrow move-hold ' +
1499
                            table_class +
1500
                            '" title="Move hold down" href="#" data-move-hold="down" data-priority="' +
1501
                            row.priority +
1502
                            '" reserve_id="' +
1503
                            row.hold_id +
1504
                            '"><i class="fa fa-lg icon-move-hold-down" aria-hidden="true"></i></a>';
1505
                        return buttons;
1506
                    },
1507
                },
1508
                {
1509
                    data: "patron.cardnumber",
1510
                    orderable: true,
1511
                    searchable: true,
1512
                    render: function (data, type, row, meta) {
1513
                        if (data == null) {
1514
                            let library = libraries.find(
1515
                                library => library._id == row.pickup_library_id
1516
                            );
1517
                            return __("A patron from library %s").format(
1518
                                library.name
1519
                            );
1520
                        } else {
1521
                            return (
1522
                                '<a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=' +
1523
                                row.patron.patron_id +
1524
                                '">' +
1525
                                data +
1526
                                "</a>"
1527
                            );
1528
                        }
1529
                    },
1530
                },
1531
                {
1532
                    data: "notes",
1533
                    orderable: false,
1534
                    searchable: false,
1535
                    render: function (data, type, row, meta) {
1536
                        return data;
1537
                    },
1538
                },
1539
                {
1540
                    data: "hold_date",
1541
                    orderable: true,
1542
                    searchable: false,
1543
                    render: function (data, type, row, meta) {
1544
                        if (AllowHoldDateInFuture) {
1545
                            return (
1546
                                '<input type="text" class="holddate ' +
1547
                                table_class +
1548
                                '" value="' +
1549
                                $date(data, { dateformat: "rfc3339" }) +
1550
                                '" size="10" name="hold_date" data-id="' +
1551
                                row.hold_id +
1552
                                '" data-current-date="' +
1553
                                data +
1554
                                '"/>'
1555
                            );
1556
                        } else {
1557
                            return $date(data);
1558
                        }
1559
                    },
1560
                },
1561
                {
1562
                    data: "expiration_date",
1563
                    orderable: true,
1564
                    searchable: false,
1565
                    render: function (data, type, row, meta) {
1566
                        return (
1567
                            '<input type="text" class="expirationdate ' +
1568
                            table_class +
1569
                            '" value="' +
1570
                            $date(data, { dateformat: "rfc3339" }) +
1571
                            '" size="10" name="expiration_date" data-id="' +
1572
                            row.hold_id +
1573
                            '" data-current-date="' +
1574
                            data +
1575
                            '"/>'
1576
                        );
1577
                    },
1578
                },
1579
                {
1580
                    data: "pickup_library_id",
1581
                    orderable: true,
1582
                    searchable: false,
1583
                    render: function (data, type, row, meta) {
1584
                        var branchSelect =
1585
                            "<select priority=" +
1586
                            row.priority +
1587
                            ' class="hold_location_select ' +
1588
                            table_class +
1589
                            '" data-id="' +
1590
                            row.hold_id +
1591
                            '" reserve_id="' +
1592
                            row.hold_id +
1593
                            '" name="pick-location" data-pickup-location-source="hold">';
1594
                        var libraryname;
1595
                        for (var i = 0; i < libraries.length; i++) {
1596
                            var selectedbranch;
1597
                            var setbranch;
1598
                            if (libraries[i]._id == data) {
1599
                                selectedbranch = " selected='selected' ";
1600
                                setbranch = __(" (current) ");
1601
                                libraryname = libraries[i]._str;
1602
                            } else if (libraries[i].pickup_location == false) {
1603
                                continue;
1604
                            } else {
1605
                                selectedbranch = "";
1606
                                setbranch = "";
1607
                            }
1608
                            branchSelect +=
1609
                                '<option value="' +
1610
                                libraries[i]._id.escapeHtml() +
1611
                                '"' +
1612
                                selectedbranch +
1613
                                ">" +
1614
                                libraries[i]._str.escapeHtml() +
1615
                                setbranch +
1616
                                "</option>";
1617
                        }
1618
                        branchSelect += "</select>";
1619
                        if (row.status == "T") {
1620
                            return __(
1621
                                "Item being transferred to <strong>%s</strong>"
1622
                            ).format(libraryname);
1623
                        } else if (row.status == "P") {
1624
                            return __(
1625
                                "Item being processed at <strong>%s</strong>"
1626
                            ).format(libraryname);
1627
                        } else if (row.status == "W") {
1628
                            return __(
1629
                                "Item waiting at <strong>%s</strong> since %s"
1630
                            ).format(libraryname, $date(row.waiting_date));
1631
                        } else {
1632
                            return branchSelect;
1633
                        }
1634
                    },
1635
                },
1636
                {
1637
                    data: "",
1638
                    orderable: false,
1639
                    searchable: false,
1640
                    render: function (data, type, row, meta) {
1641
                        if (row.status) {
1642
                            return (
1643
                                '<a href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=' +
1644
                                row.biblio_id +
1645
                                "&itemnumber=" +
1646
                                row.item_id +
1647
                                '">' +
1648
                                row.item.external_id +
1649
                                "</a>"
1650
                            );
1651
                        } else if (row.item_id && row.item_level) {
1652
                            let barcode = row.item.external_id
1653
                                ? row.item.external_id
1654
                                : __("No barcode");
1655
                            if (row.item_level_holds >= 2) {
1656
                                let link =
1657
                                    '<a href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=' +
1658
                                    row.biblio_id +
1659
                                    "&itemnumber=" +
1660
                                    row.item_id +
1661
                                    '">' +
1662
                                    (row.item.external_id
1663
                                        ? row.item.external_id.escapeHtml()
1664
                                        : __("No barcode")) +
1665
                                    "</a>";
1666
                                return __("Only item") + " " + link;
1667
                            } else {
1668
                                let select =
1669
                                    '<select id="change_hold_type" class="change_hold_type ' +
1670
                                    table_class +
1671
                                    '" data-id="' +
1672
                                    row.hold_id +
1673
                                    '">';
1674
                                select +=
1675
                                    '<option value="" selected>' +
1676
                                    __("Only item") +
1677
                                    " " +
1678
                                    barcode +
1679
                                    "</option>";
1680
                                select +=
1681
                                    '<option value="">' +
1682
                                    __("Next available") +
1683
                                    "</option>";
1684
                                select += "</select>";
1685
                                return select;
1686
                            }
1687
                        } else if (row.item_group_id) {
1688
                            return __(
1689
                                "Next available item from group <strong>%s</strong>"
1690
                            ).format(row.item_group.description);
1691
                        } else if (row.hold_group_id) {
1692
                            return (
1693
                                "<div>(" +
1694
                                __("part of") +
1695
                                ' <a href="/cgi-bin/koha/reserve/hold-group.pl?hold_group_id=' +
1696
                                row.hold_group_id +
1697
                                '" class="hold-group">' +
1698
                                __("hold group") +
1699
                                "</a>)</div>"
1700
                            );
1701
                        } else {
1702
                            if (row.non_priority) {
1703
                                return (
1704
                                    "<em>" +
1705
                                    __("Next available") +
1706
                                    "</em><br/><i>" +
1707
                                    __("Non priority hold") +
1708
                                    "</i>"
1709
                                );
1710
                            } else {
1711
                                return "<em>" + __("Next available") + "</em>";
1712
                            }
1713
                        }
1714
                    },
1715
                },
1716
                {
1717
                    data: "",
1718
                    orderable: false,
1719
                    searchable: false,
1720
                    render: function (data, type, row, meta) {
1721
                        if (row.item_id) {
1722
                            return null;
1723
                        } else {
1724
                            if (row.lowest_priority) {
1725
                                return (
1726
                                    '<a class="hold-arrow toggle-lowest-priority ' +
1727
                                    table_class +
1728
                                    '" title="Remove lowest priority" href="#" data-op="cud-setLowestPriority" data-borrowernumber="' +
1729
                                    row.patron_id +
1730
                                    '" data-biblionumber="' +
1731
                                    biblio_id +
1732
                                    '" data-reserve_id="' +
1733
                                    row.hold_id +
1734
                                    '" data-date="' +
1735
                                    row.hold_date +
1736
                                    '"><i class="fa fa-lg fa-rotate-90 icon-unset-lowest" aria-hidden="true"></i></a>'
1737
                                );
1738
                            } else {
1739
                                return (
1740
                                    '<a class="hold-arrow toggle-lowest-priority ' +
1741
                                    table_class +
1742
                                    '" title="Set lowest priority" href="#" data-op="cud-setLowestPriority" data-borrowernumber="' +
1743
                                    row.patron_id +
1744
                                    '" data-biblionumber="' +
1745
                                    biblio_id +
1746
                                    '" data-reserve_id="' +
1747
                                    row.hold_id +
1748
                                    '" data-date="' +
1749
                                    row.hold_date +
1750
                                    '"><i class="fa fa-lg fa-rotate-90 icon-set-lowest" aria-hidden="true"></i></a>'
1751
                                );
1752
                            }
1753
                        }
1754
                    },
1755
                },
1756
                {
1757
                    data: "hold_id",
1758
                    orderable: false,
1759
                    searchable: false,
1760
                    render: function (data, type, row, meta) {
1761
                        return (
1762
                            '<a class="cancel-hold deny ' +
1763
                            table_class +
1764
                            '" title="Cancel hold" data-id="' +
1765
                            data +
1766
                            '" data-biblionumber="' +
1767
                            biblio_id +
1768
                            '" data-borrowernumber="' +
1769
                            row.patron_id +
1770
                            '" href="#"><i class="fa fa-trash" aria-label="Cancel hold"></i></a>'
1771
                        );
1772
                    },
1773
                },
1774
                {
1775
                    data: "hold_id",
1776
                    orderable: false,
1777
                    searchable: false,
1778
                    render: function (data, type, row, meta) {
1779
                        if (row.status) {
1780
                            var link_value =
1781
                                row.status == "T"
1782
                                    ? __("Revert transit status")
1783
                                    : __("Revert waiting status");
1784
                            return (
1785
                                '<a class="btn btn-default submit-form-link" href="#" id="revert_hold_' +
1786
                                data +
1787
                                '" data-op="cud-move" data-where="down" data-first_priority="1" data-last_priority="' +
1788
                                totalHolds +
1789
                                '" data-prev_priority="0" data-next_priority="1" data-borrowernumber="' +
1790
                                row.patron_id +
1791
                                '" data-biblionumber="' +
1792
                                biblio_id +
1793
                                '" data-itemnumber="' +
1794
                                row.item_id +
1795
                                '" data-reserve_id="' +
1796
                                row.hold_id +
1797
                                '" data-date="' +
1798
                                row.hold_date +
1799
                                '" data-action="request.pl" data-method="post">' +
1800
                                link_value +
1801
                                "</a>"
1802
                            );
1803
                        } else {
1804
                            let td = "";
1805
                            if (SuspendHoldsIntranet) {
1806
                                td +=
1807
                                    '<button class="btn btn-default btn-xs toggle-suspend ' +
1808
                                    table_class +
1809
                                    '" data-id="' +
1810
                                    data +
1811
                                    '" data-biblionumber="' +
1812
                                    biblio_id +
1813
                                    '" data-suspended="' +
1814
                                    row.suspended +
1815
                                    '">';
1816
                                if (row.suspended) {
1817
                                    td +=
1818
                                        '<i class="fa fa-play" aria-hidden="true"></i> ' +
1819
                                        __("Unsuspend") +
1820
                                        "</button>";
1821
                                } else {
1822
                                    td +=
1823
                                        '<i class="fa fa-pause" aria-hidden="true"></i> ' +
1824
                                        __("Suspend") +
1825
                                        "</button>";
1826
                                }
1827
                                if (AutoResumeSuspendedHolds) {
1828
                                    if (row.suspended) {
1829
                                        td +=
1830
                                            '<label for="suspend_until_' +
1831
                                            data +
1832
                                            '">' +
1833
                                            __("Suspend on") +
1834
                                            " </label>";
1835
                                    } else {
1836
                                        td +=
1837
                                            '<label for="suspend_until_' +
1838
                                            data +
1839
                                            '">' +
1840
                                            __("Suspend until") +
1841
                                            " </label>";
1842
                                    }
1843
                                    td +=
1844
                                        '<input type="text" name="suspend_until_' +
1845
                                        data +
1846
                                        '" data-id="' +
1847
                                        data +
1848
                                        '" size="10" value="' +
1849
                                        $date(row.suspended_until, {
1850
                                            dateformat: "rfc3339",
1851
                                        }) +
1852
                                        '" class="suspenddate ' +
1853
                                        table_class +
1854
                                        '" data-flatpickr-futuredate="true" data-suspend-date="' +
1855
                                        row.suspended_until +
1856
                                        '" />';
1857
                                }
1858
                                return td;
1859
                            } else {
1860
                                return null;
1861
                            }
1862
                        }
1863
                    },
1864
                },
1865
                {
1866
                    data: "hold_id",
1867
                    orderable: false,
1868
                    searchable: false,
1869
                    render: function (data, type, row, meta) {
1870
                        if (row.status == "W" || row.status == "T") {
1871
                            return (
1872
                                '<a class="btn btn-default btn-xs printholdslip ' +
1873
                                table_class +
1874
                                '" data-reserve_id="' +
1875
                                data +
1876
                                '">' +
1877
                                __("Print slip") +
1878
                                "</a>"
1879
                            );
1880
                        } else {
1881
                            return "";
1882
                        }
1883
                    },
1884
                },
1885
            ],
1886
        },
1887
        hold_table_settings
1888
    );
1889
    holdsQueueTable.api().page(0).draw(false);
1890
    // Clear selectedHolds on page load
1891
    localStorage.removeItem("selectedHolds");
1892
    $(table_id).on("draw.dt", function () {
1893
        // Always deselect the "select all" checkbox when the page changes
1894
        $(".holds_table .select_hold_all").prop("checked", false);
1895
        updateMSGCounters();
1896
        $(".holds_table .select_hold." + table_class).each(function () {
1897
            const selected = JSON.parse(localStorage.selectedHolds || "[]");
1898
            const holdId = $(this).data("id");
1899
            if (selected.some(s => s.hold === holdId)) {
1900
                $(this).prop("checked", true);
1901
                $(this).parent().parent().addClass("selected");
1902
                var table = $(this).closest(".holds_table");
1903
                var count = $(
1904
                    ".select_hold." + table_class + ":not(:checked)",
1905
                    table
1906
                ).length;
1907
                $(".select_hold_all." + table_class, table).prop(
1908
                    "checked",
1909
                    !count
1910
                );
1911
            }
1912
        });
1913
        $(".holds_table .select_hold_all").on("click", function () {
1914
            var table = $(this).closest(".holds_table");
1915
            var isChecked = $(this).prop("checked");
1916
            var allCheckboxes = table
1917
                .DataTable()
1918
                .rows({ search: "applied" })
1919
                .nodes();
1920
            let selected = JSON.parse(localStorage.selectedHolds || "[]");
1921
            let pageHolds = [];
1922
1923
            $("input.select_hold", allCheckboxes).each(function () {
1924
                let hold_data = {
1925
                    hold: $(this).data("id"),
1926
                    borrowernumber: $(this).data("borrowernumber"),
1927
                    biblionumber: $(this).data("biblionumber"),
1928
                    itemnumber: $(this).data("itemnumber"),
1929
                    waiting: $(this).data("waiting"),
1930
                    intransit: $(this).data("intransit"),
1931
                    status: $(this).data("status"),
1932
                    item_level_hold: $(this).data("item_level_hold"),
1933
                    hold_group_id: $(this).data("hold-group-id"),
1934
                };
1935
                pageHolds.push(hold_data);
1936
            });
1937
1938
            if (isChecked) {
1939
                // Add all page holds to the selection, avoiding duplicates
1940
                pageHolds.forEach(hold => {
1941
                    if (!selected.some(s => s.hold === hold.hold)) {
1942
                        selected.push(hold);
1943
                    }
1944
                });
1945
                $("input.select_hold", allCheckboxes).prop("checked", true);
1946
                $("input.select_hold", allCheckboxes).each(function () {
1947
                    $(this).parent().parent().addClass("selected");
1948
                });
1949
            } else {
1950
                // Remove all page holds from the selection
1951
                const pageIds = pageHolds.map(h => h.hold);
1952
                selected = selected.filter(s => !pageIds.includes(s.hold));
1953
                $("input.select_hold", allCheckboxes).prop("checked", false);
1954
                $("input.select_hold", allCheckboxes).each(function () {
1955
                    $(this).parent().parent().removeClass("selected");
1956
                });
1957
            }
1958
1959
            localStorage.selectedHolds = JSON.stringify(selected);
1960
            $("#cancel_hold_alert").html(
1961
                MSG_CANCEL_ALERT.format(selected.length)
1962
            );
1963
            updateMoveButtons();
1964
            updateMSGCounters();
1965
            $("#cancel_hold_alert").show();
1966
        });
1967
        function updateMoveButtons() {
1968
            var checked_holds = JSON.parse(localStorage.selectedHolds || "[]");
1969
            var checked_count = checked_holds.length;
1970
1971
            var item_level_count = checked_holds.filter(function (hold) {
1972
                return hold.item_level_hold > 0;
1973
            }).length;
1974
1975
            var record_level_count = checked_holds.filter(function (hold) {
1976
                return hold.item_level_hold === 0;
1977
            }).length;
1978
1979
            $(".move_hold_item").toggleClass("disabled", item_level_count <= 0);
1980
            $(".move_hold_biblio").toggleClass(
1981
                "disabled",
1982
                record_level_count <= 0
1983
            );
1984
            $(".move_selected_holds").prop("disabled", !checked_count);
1985
        }
1986
1987
        function updateMSGCounters() {
1988
            var MSG_CANCEL_SELECTED = __("Cancel selected (%s)");
1989
            var MSG_MOVE_SELECTED = __("Move selected (%s)");
1990
            var MSG_CANCEL_ALERT = __(
1991
                "This action will cancel <span class='badge bg-danger'>%s</span> hold(s)."
1992
            );
1993
            var selectedCount = JSON.parse(
1994
                localStorage.selectedHolds || "[]"
1995
            ).length;
1996
            $(".cancel_selected_holds").html(
1997
                MSG_CANCEL_SELECTED.format(selectedCount)
1998
            );
1999
            $(".move_selected_holds").html(
2000
                MSG_MOVE_SELECTED.format(selectedCount)
2001
            );
2002
            $("#cancel_hold_alert").html(
2003
                MSG_CANCEL_ALERT.format(selectedCount)
2004
            );
2005
        }
2006
2007
        $(".holds_table .select_hold").on("click", function () {
2008
            let selected = JSON.parse(localStorage.selectedHolds || "[]");
2009
            const hold_data = {
2010
                hold: $(this).data("id"),
2011
                borrowernumber: $(this).data("borrowernumber"),
2012
                biblionumber: $(this).data("biblionumber"),
2013
                itemnumber: $(this).data("itemnumber"),
2014
                waiting: $(this).data("waiting"),
2015
                intransit: $(this).data("intransit"),
2016
                status: $(this).data("status"),
2017
                item_level_hold: $(this).data("item_level_hold"),
2018
                hold_group_id: $(this).data("hold-group-id"),
2019
            };
2020
            if ($(this).is(":checked")) {
2021
                if (!selected.some(s => s.hold === hold_data.hold)) {
2022
                    selected.push(hold_data);
2023
                }
2024
            } else {
2025
                selected = selected.filter(s => s.hold !== hold_data.hold);
2026
            }
2027
            localStorage.selectedHolds = JSON.stringify(selected);
2028
            updateMoveButtons();
2029
            updateMSGCounters();
2030
            $("#cancel_hold_alert").show();
2031
            var table = $(this).parents(".holds_table");
2032
            var count = $(".select_hold:not(:checked)", table).length;
2033
            $(".select_hold_all", table).prop("checked", !count);
2034
            $(this).parent().parent().toggleClass("selected");
2035
        });
2036
        $(".cancel-hold." + table_class).on("click", function (e) {
2037
            e.preventDefault;
2038
            cancel_link = $(this);
2039
            $("#cancel_modal_form #inputs").empty();
2040
            let reserve_id = cancel_link.data("id");
2041
            let biblionumber = cancel_link.data("biblionumber");
2042
            _append_patron_page_cancel_hold_modal_data({
2043
                hold: reserve_id,
2044
                biblionumber: biblionumber,
2045
                borrowernumber: cancel_link.data("borrowernumber"),
2046
            });
2047
            $("#cancelModal").modal("show");
2048
        });
2049
        $(".cancel_selected_holds").click(function (e) {
2050
            e.preventDefault();
2051
            const selectedHolds = JSON.parse(
2052
                localStorage.selectedHolds || "[]"
2053
            );
2054
            if (selectedHolds.length) {
2055
                $("#cancel_modal_form #inputs").empty();
2056
2057
                selectedHolds.forEach(function (hold) {
2058
                    _append_patron_page_cancel_hold_modal_data(hold);
2059
                });
2060
2061
                delete localStorage.selectedHolds;
2062
                $("#cancelModal").modal("show");
2063
            }
2064
            return false;
2065
        });
2066
        function _append_patron_page_cancel_hold_modal_data(hold) {
2067
            $("#cancel_modal_form #inputs").append(
2068
                '<input type="hidden" name="rank-request" value="del">'
2069
            );
2070
            $("#cancel_modal_form #inputs").append(
2071
                '<input type="hidden" name="biblionumber" value="' +
2072
                    hold.biblionumber +
2073
                    '">'
2074
            );
2075
            $("#cancel_modal_form #inputs").append(
2076
                '<input type="hidden" name="borrowernumber" value="' +
2077
                    hold.borrowernumber +
2078
                    '">'
2079
            );
2080
            $("#cancel_modal_form #inputs").append(
2081
                '<input type="hidden" name="reserve_id" value="' +
2082
                    hold.hold +
2083
                    '">'
2084
            );
2085
        }
2086
        // Remove any previously attached handlers
2087
        $("#cancelModalConfirmBtn").off("click");
2088
        // Attach the handler to the button
2089
        $("#cancelModalConfirmBtn").one("click", function (e) {
2090
            e.preventDefault();
2091
            let formInputs = {};
2092
            formInputs["reserve_id"] = $(
2093
                "#cancel_modal_form :input[name='reserve_id']"
2094
            )
2095
                .map(function () {
2096
                    return $(this).val();
2097
                })
2098
                .get();
2099
            formInputs["cancellation-reason"] = $(
2100
                "#cancel_modal_form :input[name='cancellation-reason']"
2101
            ).val();
2102
            cancel_holds(
2103
                formInputs["reserve_id"],
2104
                formInputs["cancellation-reason"]
2105
            )
2106
                .success(function () {
2107
                    holdsQueueTable.api().ajax.reload(null, false);
2108
                })
2109
                .fail(function (jqXHR) {
2110
                    $("#cancelModal .modal-body").prepend(
2111
                        '<div class="alert alert-danger">' +
2112
                            jqXHR.responseJSON.error +
2113
                            "</div>"
2114
                    );
2115
                    $("#cancelModalConfirmBtn").prop("disabled", true);
2116
                })
2117
                .done(function () {
2118
                    $("#cancelModal").modal("hide");
2119
                    if ($(".select_hold_all").prop("checked")) {
2120
                        $(".select_hold_all").click();
2121
                    }
2122
                });
2123
        });
2124
        function cancel_holds(hold_ids, cancellation_reason) {
2125
            return $.ajax({
2126
                method: "DELETE",
2127
                url: "/api/v1/holds/cancellation_bulk",
2128
                contentType: "application/json",
2129
                data: JSON.stringify({
2130
                    hold_ids: hold_ids,
2131
                    cancellation_reason: cancellation_reason,
2132
                }),
2133
            });
2134
        }
2135
        $(
2136
            ".holddate." + table_class + ", .expirationdate." + table_class
2137
        ).flatpickr({
2138
            onReady: function (selectedDates, dateStr, instance) {
2139
                $(instance.altInput)
2140
                    .wrap("<span class='flatpickr_wrapper'></span>")
2141
                    .after(
2142
                        $("<a/>")
2143
                            .attr("href", "#")
2144
                            .addClass("clear_date")
2145
                            .addClass("fa fa-times")
2146
                            .addClass("ps-2")
2147
                            .on("click", function (e) {
2148
                                e.preventDefault();
2149
                                instance.clear();
2150
                            })
2151
                            .attr("aria-hidden", true)
2152
                    );
2153
            },
2154
            onChange: function (selectedDates, dateStr, instance) {
2155
                let hold_id = $(instance.input).attr("data-id");
2156
                let fieldname = $(instance.input).attr("name");
2157
                let current_date = $(instance.input).attr("data-current-date");
2158
                dateStr = dateStr ? dateStr : null;
2159
                let req =
2160
                    fieldname == "hold_date"
2161
                        ? { hold_date: dateStr }
2162
                        : { expiration_date: dateStr };
2163
                if (current_date != dateStr) {
2164
                    $.ajax({
2165
                        method: "PATCH",
2166
                        url: "/api/v1/holds/" + encodeURIComponent(hold_id),
2167
                        contentType: "application/json",
2168
                        data: JSON.stringify(req),
2169
                        success: function (data) {
2170
                            holdsQueueTable.api().ajax.reload(null, false);
2171
                            $(instance.input).attr(
2172
                                "data-current-date",
2173
                                dateStr
2174
                            );
2175
                        },
2176
                        error: function (jqXHR, textStatus, errorThrown) {
2177
                            holdsQueueTable.api().ajax.reload(null, false);
2178
                        },
2179
                    });
2180
                }
2181
            },
2182
        });
2183
        $(".suspenddate." + table_class).flatpickr({
2184
            onReady: function (selectedDates, dateStr, instance) {
2185
                $(instance.altInput)
2186
                    .wrap("<span class='flatpickr_wrapper'></span>")
2187
                    .after(
2188
                        $("<a/>")
2189
                            .attr("href", "#")
2190
                            .addClass("clear_date")
2191
                            .addClass("fa fa-times")
2192
                            .addClass("ps-2")
2193
                            .on("click", function (e) {
2194
                                e.preventDefault();
2195
                                instance.clear();
2196
                            })
2197
                            .attr("aria-hidden", true)
2198
                    );
2199
            },
2200
        });
2201
        $(".toggle-suspend." + table_class).one("click", function (e) {
2202
            e.preventDefault();
2203
            const hold_id = $(this).data("id");
2204
            const suspended = $(this).attr("data-suspended");
2205
            const input = $(
2206
                `.suspenddate.` + table_class + `[data-id="${hold_id}"]`
2207
            );
2208
            const method = suspended == "true" ? "DELETE" : "POST";
2209
            let end_date = input.val() && method == "POST" ? input.val() : null;
2210
            let params =
2211
                end_date !== null && end_date !== ""
2212
                    ? JSON.stringify({ end_date: end_date })
2213
                    : null;
2214
            $.ajax({
2215
                method: method,
2216
                url:
2217
                    "/api/v1/holds/" +
2218
                    encodeURIComponent(hold_id) +
2219
                    "/suspension",
2220
                contentType: "application/json",
2221
                data: params,
2222
                success: function (data) {
2223
                    holdsQueueTable.api().ajax.reload(null, false);
2224
                },
2225
                error: function (jqXHR, textStatus, errorThrown) {
2226
                    holdsQueueTable.api().ajax.reload(null, false);
2227
                    alert(
2228
                        "There was an error:" + textStatus + " " + errorThrown
2229
                    );
2230
                },
2231
            });
2232
        });
2233
        $(".rank-request." + table_class).on("change", function (e) {
2234
            e.preventDefault();
2235
            const hold_id = $(this).data("id");
2236
            let priority = e.target.value;
2237
            // Replace select with spinner
2238
            const $select = $(this);
2239
            const $spinner = $(
2240
                '<img class="rank-spinner" src="/intranet-tmpl/prog/img/spinner-small.gif" alt="Loading..." style="display:block;margin:0 auto;vertical-align:middle;">'
2241
            );
2242
            $select.hide().after($spinner);
2243
            $.ajax({
2244
                method: "PUT",
2245
                url:
2246
                    "/api/v1/holds/" +
2247
                    encodeURIComponent(hold_id) +
2248
                    "/priority",
2249
                data: JSON.stringify(priority),
2250
                success: function (data) {
2251
                    holdsQueueTable.api().ajax.reload(null, false);
2252
                    $spinner.remove();
2253
                },
2254
                error: function (jqXHR, textStatus, errorThrown) {
2255
                    alert(
2256
                        "There was an error:" + textStatus + " " + errorThrown
2257
                    );
2258
                    $select.show();
2259
                    $spinner.remove();
2260
                },
2261
            });
2262
        });
2263
        $(".move-hold." + table_class).one("click", function (e) {
2264
            e.preventDefault();
2265
            let toPosition = $(this).attr("data-move-hold");
2266
            let priority = $(this).attr("data-priority");
2267
            var res_id = $(this).attr("reserve_id");
2268
            var moveTo;
2269
            if (toPosition == "up") {
2270
                moveTo = parseInt(priority) - 1;
2271
            }
2272
            if (toPosition == "down") {
2273
                moveTo = parseInt(priority) + 1;
2274
            }
2275
            if (toPosition == "top") {
2276
                moveTo = 1;
2277
            }
2278
            if (toPosition == "bottom") {
2279
                moveTo = totalHolds;
2280
            }
2281
            $.ajax({
2282
                method: "PUT",
2283
                url:
2284
                    "/api/v1/holds/" + encodeURIComponent(res_id) + "/priority",
2285
                data: JSON.stringify(moveTo),
2286
                success: function (data) {
2287
                    holdsQueueTable.api().ajax.reload(null, false);
2288
                },
2289
                error: function (jqXHR, textStatus, errorThrown) {
2290
                    alert(
2291
                        "There was an error:" + textStatus + " " + errorThrown
2292
                    );
2293
                },
2294
            });
2295
        });
2296
        $(".toggle-lowest-priority." + table_class).one("click", function (e) {
2297
            e.preventDefault();
2298
            var res_id = $(this).attr("data-reserve_id");
2299
            $.ajax({
2300
                method: "PUT",
2301
                url:
2302
                    "/api/v1/holds/" +
2303
                    encodeURIComponent(res_id) +
2304
                    "/lowest_priority",
2305
                success: function (data) {
2306
                    holdsQueueTable.api().ajax.reload(null, false);
2307
                },
2308
                error: function (jqXHR, textStatus, errorThrown) {
2309
                    alert(
2310
                        "There was an error:" + textStatus + " " + errorThrown
2311
                    );
2312
                },
2313
            });
2314
        });
2315
        $(".hold_location_select." + table_class).on("change", function () {
2316
            $(this).prop("disabled", true);
2317
            var cur_select = $(this);
2318
            var res_id = $(this).attr("reserve_id");
2319
            $(this).after(
2320
                '<div id="updating_reserveno' +
2321
                    res_id +
2322
                    '" class="waiting"><img src="/intranet-tmpl/prog/img/spinner-small.gif" alt="" /><span class="waiting_msg"></span></div>'
2323
            );
2324
            let api_url =
2325
                "/api/v1/holds/" +
2326
                encodeURIComponent(res_id) +
2327
                "/pickup_location";
2328
            $.ajax({
2329
                method: "PUT",
2330
                url: api_url,
2331
                data: JSON.stringify({ pickup_library_id: $(this).val() }),
2332
                headers: { "x-koha-override": "any" },
2333
                success: function (data) {
2334
                    holdsQueueTable.api().ajax.reload(null, false);
2335
                },
2336
                error: function (jqXHR, textStatus, errorThrown) {
2337
                    alert(
2338
                        "There was an error:" + textStatus + " " + errorThrown
2339
                    );
2340
                    cur_select.prop("disabled", false);
2341
                    $("#updating_reserveno" + res_id).remove();
2342
                    cur_select.val(
2343
                        cur_select.children('option[selected="selected"]').val()
2344
                    );
2345
                },
2346
            });
2347
        });
2348
        $(".change_hold_type." + table_class).on("change", function () {
2349
            $(this).prop("disabled", true);
2350
            var cur_select = $(this);
2351
            var hold_id = $(this).attr("data-id");
2352
            $(this).after(
2353
                '<div id="updating_holdno' +
2354
                    hold_id +
2355
                    '" class="waiting"><img src="/intranet-tmpl/prog/img/spinner-small.gif" alt="" /><span class="waiting_msg"></span></div>'
2356
            );
2357
            let api_url = "/api/v1/holds/" + encodeURIComponent(hold_id);
2358
            $.ajax({
2359
                method: "PATCH",
2360
                url: api_url,
2361
                data: JSON.stringify({ item_id: null, item_level: false }),
2362
                headers: { "x-koha-override": "any" },
2363
                contentType: "application/json",
2364
                success: function (data) {
2365
                    holdsQueueTable.api().ajax.reload(null, false);
2366
                },
2367
                error: function (jqXHR, textStatus, errorThrown) {
2368
                    alert(
2369
                        "There was an error:" + textStatus + " " + errorThrown
2370
                    );
2371
                    cur_select.prop("disabled", false);
2372
                    $("#updating_holdno" + hold_id).remove();
2373
                    cur_select.val(
2374
                        cur_select.children('option[selected="selected"]').val()
2375
                    );
2376
                },
2377
            });
2378
        });
2379
        $(".printholdslip." + table_class).one("click", function () {
2380
            var reserve_id = $(this).attr("data-reserve_id");
2381
            window.open(
2382
                "/cgi-bin/koha/circ/hold-transfer-slip.pl?reserve_id=" +
2383
                    reserve_id
2384
            );
2385
            return false;
2386
        });
2387
    });
2388
}
(-)a/reserve/request.pl (-62 / +33 lines)
Lines 668-676 if ( ( $findborrower && $borrowernumber_hold || $findclub && $club_hold ) Link Here
668
668
669
        # existingreserves building
669
        # existingreserves building
670
        my @reserveloop;
670
        my @reserveloop;
671
        my $total_holds       = 0;
672
        my $hold_branches     = [];
673
        my $hold_itemtypes    = [];
671
        my $always_show_holds = $input->cookie('always_show_holds');
674
        my $always_show_holds = $input->cookie('always_show_holds');
672
        $template->param( always_show_holds => $always_show_holds );
675
        $template->param( always_show_holds => $always_show_holds );
673
        my $show_holds_now = $input->param('show_holds_now');
676
        my $show_holds_now = $input->param('show_holds_now');
677
674
        unless ( ( defined $always_show_holds && $always_show_holds eq 'DONT' ) && !$show_holds_now ) {
678
        unless ( ( defined $always_show_holds && $always_show_holds eq 'DONT' ) && !$show_holds_now ) {
675
            my $holds_count_per_patron = {
679
            my $holds_count_per_patron = {
676
                map { $_->{borrowernumber} => $_->{hold_count} } @{ Koha::Holds->search(
680
                map { $_->{borrowernumber} => $_->{hold_count} } @{ Koha::Holds->search(
Lines 683-746 if ( ( $findborrower && $borrowernumber_hold || $findclub && $club_hold ) Link Here
683
                    )->unblessed
687
                    )->unblessed
684
                }
688
                }
685
            };
689
            };
686
            my @reserves = Koha::Holds->search(
690
            $total_holds = Koha::Holds->search( { biblionumber => $biblionumber } )->count;
687
                { 'me.biblionumber' => $biblionumber },
691
            my $branches = Koha::Holds->search(
688
                { prefetch          => [ 'borrowernumber', 'itemnumber' ], order_by => 'priority' }
692
                {
689
            )->as_list;
693
                    biblionumber => $biblionumber,
690
            foreach my $res (
694
                },
691
                sort {
695
                {
692
                    my $a_found = $a->found() || '';
696
                    select => [ { distinct => 'branchcode' } ],
693
                    my $b_found = $a->found() || '';
697
                    as     => [qw( branchcode )],
694
                    $a_found cmp $b_found;
695
                } @reserves
696
                )
697
            {
698
                my %reserve;
699
                if ( $res->is_found() ) {
700
                    $reserve{'holdingbranch'} = $res->item()->holdingbranch();
701
                    $reserve{'biblionumber'}  = $res->item()->biblionumber();
702
                    $reserve{'barcodenumber'} = $res->item()->barcode();
703
                    $reserve{'wbrcode'}       = $res->branchcode();
704
                    $reserve{'itemnumber'}    = $res->itemnumber();
705
                    $reserve{'wbrname'}       = $res->branch()->branchname();
706
                    $reserve{'atdestination'} = $res->is_at_destination();
707
                    $reserve{'desk_name'}     = ( $res->desk() ) ? $res->desk()->desk_name() : '';
708
                    $reserve{'found'}         = $res->is_found();
709
                    $reserve{'inprocessing'}  = $res->is_in_processing();
710
                    $reserve{'intransit'}     = $res->is_in_transit();
711
                } elsif ( $res->priority() > 0 ) {
712
                    if ( my $item = $res->item() ) {
713
                        $reserve{'itemnumber'}      = $item->id();
714
                        $reserve{'barcodenumber'}   = $item->barcode();
715
                        $reserve{'item_level_hold'} = 1;
716
                    }
717
                }
698
                }
718
                $reserve{'expirationdate'} = $res->expirationdate;
699
            )->unblessed;
719
                $reserve{'date'}           = $res->reservedate;
700
            $hold_branches = [ map { $_->{branchcode} } @$branches ];
720
                $reserve{'borrowernumber'} = $res->borrowernumber();
701
            my $itemtypes = Koha::Holds->search(
721
                $reserve{'biblionumber'}   = $res->biblionumber();
702
                {
722
                $reserve{'patron'}         = $res->borrower;
703
                    biblionumber => $biblionumber,
723
                $reserve{'notes'}          = $res->reservenotes();
704
                },
724
                $reserve{'waiting_date'}   = $res->waitingdate();
705
                {
725
                $reserve{'ccode'}          = $res->item() ? $res->item()->ccode()   : undef;
706
                    select => [ { distinct => 'itemtype' } ],
726
                $reserve{'barcode'}        = $res->item() ? $res->item()->barcode() : undef;
707
                    as     => [qw( itemtype )],
727
                $reserve{'priority'}       = $res->priority();
728
                $reserve{'lowestPriority'} = $res->lowestPriority();
729
                $reserve{'suspend'}        = $res->suspend();
730
                $reserve{'suspend_until'}  = $res->suspend_until();
731
                $reserve{'reserve_id'}     = $res->reserve_id();
732
                $reserve{itemtype}         = $res->itemtype();
733
                $reserve{branchcode}       = $res->branchcode();
734
                $reserve{non_priority}     = $res->non_priority();
735
                $reserve{object}           = $res;
736
                $reserve{hold_group_id}    = $res->hold_group_id;
737
738
                if ( $holds_count_per_patron->{ $reserve{'borrowernumber'} } == 1 ) {
739
                    $reserve{'change_hold_type_allowed'} = 1;
740
                }
708
                }
741
709
            )->unblessed;
742
                push( @reserveloop, \%reserve );
710
            $hold_itemtypes = [ map { $_->{itemtype} ? $_->{itemtype} : 'any' } @$itemtypes ];
743
            }
744
        }
711
        }
745
712
746
        # get the time for the form name...
713
        # get the time for the form name...
Lines 763-778 if ( ( $findborrower && $borrowernumber_hold || $findclub && $club_hold ) Link Here
763
            C4::Search::enabled_staff_search_views,
730
            C4::Search::enabled_staff_search_views,
764
        );
731
        );
765
732
766
        $biblioloopiter{biblionumber} = $biblionumber;
733
        $biblioloopiter{biblionumber}   = $biblionumber;
767
        $biblioloopiter{title}        = $biblio->title;
734
        $biblioloopiter{title}          = $biblio->title;
768
        $biblioloopiter{author}       = $biblio->author;
735
        $biblioloopiter{author}         = $biblio->author;
769
        $biblioloopiter{rank}         = $fixedRank;
736
        $biblioloopiter{rank}           = $fixedRank;
770
        $biblioloopiter{reserveloop}  = \@reserveloop;
737
        $biblioloopiter{reserveloop}    = \@reserveloop;
738
        $biblioloopiter{total_holds}    = $total_holds;
739
        $biblioloopiter{hold_branches}  = $hold_branches;
740
        $biblioloopiter{hold_itemtypes} = $hold_itemtypes;
771
741
772
        if (@reserveloop) {
742
        if (@reserveloop) {
773
            $template->param( reserveloop => \@reserveloop );
743
            $template->param( reserveloop => \@reserveloop );
774
        }
744
        }
775
745
746
        $template->param( total_holds => $total_holds );
747
776
        if ( $patron && $multi_hold ) {
748
        if ( $patron && $multi_hold ) {
777
749
778
            # Add the valid pickup locations
750
            # Add the valid pickup locations
779
- 

Return to bug 23269