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 2115-2120 modules: Link Here
2115
              columnname: action
2115
              columnname: action
2116
2116
2117
      patron_holds_table:
2117
      patron_holds_table:
2118
        default_sort_order: 1
2118
        columns:
2119
        columns:
2119
            -
2120
            -
2120
              columnname: checkbox
2121
              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 1311-1317 Link Here
1311
                [% END %]
1311
                [% END %]
1312
            [% END %]
1312
            [% END %]
1313
        [% END %]
1313
        [% END %]
1314
        [% IF ( reserveloop ) %]
1314
        [% IF ( total_holds ) %]
1315
            <form id="existing_holds" name="T[% time | html %]" action="modrequest.pl" method="post" style="display:block">
1315
            <form id="existing_holds" name="T[% time | html %]" action="modrequest.pl" method="post" style="display:block">
1316
                [% INCLUDE 'csrf-token.inc' %]
1316
                [% INCLUDE 'csrf-token.inc' %]
1317
                [% IF ( multi_hold ) %]
1317
                [% IF ( multi_hold ) %]
Lines 1330-1340 Link Here
1330
                <h2>Existing holds</h2>
1330
                <h2>Existing holds</h2>
1331
                <div id="toolbar" class="btn-toolbar sticky">
1331
                <div id="toolbar" class="btn-toolbar sticky">
1332
                    <div class="btn-group">
1332
                    <div class="btn-group">
1333
                        <input type="hidden" name="op" value="cud-modifyall" />
1333
                        <button class="btn cancel_selected_holds" data-bulk="true"></button>
1334
                        <input type="submit" class="btn btn-primary" name="submit" value="Update hold(s)" />
1335
                    </div>
1336
                    <div class="btn-group">
1337
                        <button class="btn cancel_selected_holds" data-bulk="true"> Cancel selected (<span class="selected_holds_count"></span>)</button>
1338
                    </div>
1334
                    </div>
1339
                    <div id="cancellation-reason-div" style="display:none">
1335
                    <div id="cancellation-reason-div" style="display:none">
1340
                        [% SET hold_cancellation = AuthorisedValues.GetAuthValueDropbox('HOLD_CANCELLATION') %]
1336
                        [% SET hold_cancellation = AuthorisedValues.GetAuthValueDropbox('HOLD_CANCELLATION') %]
Lines 1360-1496 Link Here
1360
                </div>
1356
                </div>
1361
                <div class="page-section">
1357
                <div class="page-section">
1362
                    [% FOREACH biblioloo IN biblioloop %]
1358
                    [% FOREACH biblioloo IN biblioloop %]
1363
                        [% IF ( biblioloo.reserveloop ) %]
1359
                        [% IF ( biblioloo.total_holds ) %]
1364
                            <div class="hold_title" id="hold_title_[% biblioloo.biblionumber | html %]">
1360
                            <div class="hold_title" id="hold_title_[% biblioloo.biblionumber | html %]">
1365
                                [% IF ( multi_hold ) %]
1361
                                [% IF ( multi_hold ) %]
1366
                                    <h3>
1362
                                    <h3>
1367
                                        <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% biblioloo.biblionumber | uri %]"> [% biblioloo.title | html %] </a>
1363
                                        <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% biblioloo.biblionumber | uri %]"> [% biblioloo.title | html %] </a>
1368
                                        <span class="badge bg-info-subtle"><span>[% biblioloo.reserveloop.size | html %] [% tn('Hold', 'Holds', biblioloo.reserveloop.size) | $raw %]</span></span>
1364
                                        <span class="badge bg-info-subtle"><span>[% biblioloo.total_holds | html %] [% tn('Hold', 'Holds', biblioloo.total_holds) | $raw %]</span></span>
1369
                                    </h3>
1365
                                    </h3>
1370
                                [% END %]
1366
                                [% END %]
1371
1367
1372
                                [% IF Koha.Preference('HoldsSplitQueue') == 'branch' %]
1368
                                [% IF Koha.Preference('HoldsSplitQueue') == 'branch' %]
1373
1369
                                    [% IF biblioloo.hold_branches.empty %]
1374
                                    [% SET branchcodes = [] %]
1370
                                        <div class="holds_by_library">
1375
1371
                                            <h4>Any library</h4>
1376
                                    [% FOREACH h IN biblioloo.reserveloop %]
1372
                                            [% INCLUDE holds_table.inc biblio_id=biblioloo.biblionumber total_holds=biblioloo.total_holds split_data="any" %]
1377
                                        [% branchcodes.push( h.branchcode ) %]
1373
                                        </div>
1378
                                    [% END %]
1379
                                    [% branchcodes = branchcodes.unique %]
1380
                                    [% IF ( branchcodes.empty ) %]
1381
                                        <div class="alert alert-info"> There are no holds on this title. </div>
1382
                                    [% ELSE %]
1374
                                    [% ELSE %]
1383
1375
                                        [% FOREACH b IN biblioloo.hold_branches %]
1384
                                        [% FOREACH b IN branchcodes.sort %]
1385
                                            [% SET holds_by_branch = [] %]
1386
                                            [% FOREACH h IN biblioloo.reserveloop %]
1387
                                                [% IF h.branchcode == b %]
1388
                                                    [% holds_by_branch.push( h ) %]
1389
                                                [% END %]
1390
                                            [% END %]
1391
                                            <div class="holds_by_library">
1376
                                            <div class="holds_by_library">
1392
                                                <h4>[% Branches.GetName( b ) | html %]</h4>
1377
                                                <h4>[% Branches.GetName( b ) | html %]</h4>
1393
1378
1394
                                                [% INCLUDE holds_table.inc holds=holds_by_branch %]
1379
                                                [% INCLUDE holds_table.inc biblio_id=biblioloo.biblionumber total_holds=biblioloo.total_holds split_data=b %]
1395
                                            </div>
1380
                                            </div>
1396
                                        [% END # /FOREACh b %]
1381
                                        [% END %]
1397
                                    [% END # /IF ( branchcodes.empty ) %]
1382
                                    [% END # /IF hold_branches.empty %]
1398
                                [% ELSIF Koha.Preference('HoldsSplitQueue') == 'itemtype' %]
1383
                                [% ELSIF Koha.Preference('HoldsSplitQueue') == 'itemtype' %]
1399
1384
1400
                                    [% SET itemtypes = [] %]
1385
                                    [% IF biblioloo.hold_itemtypes.empty %]
1401
1386
                                        <div class="holds_by_itemtype">
1402
                                    [% FOREACH h IN biblioloo.reserveloop %]
1387
                                            <h4>Any item type</h4>
1403
                                        [% SET hold_itemtype = h.object.item.effective_itemtype || h.itemtype %]
1388
                                            [% INCLUDE holds_table.inc biblio_id=biblioloo.biblionumber total_holds=biblioloo.total_holds split_data="any" %]
1404
                                        [% itemtypes.push( hold_itemtype ) %]
1389
                                        </div>
1405
                                    [% END %]
1406
                                    [% itemtypes = itemtypes.unique %]
1407
                                    [% IF ( itemtypes.empty ) %]
1408
                                        <div class="alert alert-info"> There are no holds on this title. </div>
1409
                                    [% ELSE %]
1390
                                    [% ELSE %]
1410
1391
                                        [% FOREACH i IN biblioloo.hold_itemtypes %]
1411
                                        [% FOREACH i IN itemtypes.sort %]
1412
                                            [% SET holds_by_itemtype = [] %]
1413
                                            [% FOREACH h IN biblioloo.reserveloop %]
1414
                                                [% SET hold_itemtype = h.object.item.effective_itemtype || h.itemtype %]
1415
                                                [% IF hold_itemtype == i %]
1416
                                                    [% holds_by_itemtype.push( h ) %]
1417
                                                [% END %]
1418
                                            [% END %]
1419
1420
                                            <div class="holds_by_itemtype">
1392
                                            <div class="holds_by_itemtype">
1421
                                                [% IF i %]
1393
                                                [% IF i && i != 'any' %]
1422
                                                    <h4>[% ItemTypes.GetDescription( i ) | html %]</h4>
1394
                                                    <h4>[% ItemTypes.GetDescription( i ) | html %]</h4>
1423
                                                [% ELSE %]
1395
                                                [% ELSE %]
1424
                                                    <h4>Any item type</h4>
1396
                                                    <h4>Any item type</h4>
1425
                                                [% END %]
1397
                                                [% END %]
1426
                                                [% INCLUDE holds_table.inc holds=holds_by_itemtype %]
1398
                                                [% INCLUDE holds_table.inc biblio_id=biblioloo.biblionumber total_holds=biblioloo.total_holds split_data=i %]
1427
                                            </div>
1399
                                            </div>
1428
                                        [% END # /FOREACH i %]
1400
                                        [% END %]
1429
                                    [% END # /IF ( itemtypes.empty ) %]
1401
                                    [% END # /IF hold_split.empty %]
1430
                                [% ELSIF Koha.Preference('HoldsSplitQueue') == 'branch_itemtype' %]
1402
                                [% ELSIF Koha.Preference('HoldsSplitQueue') == 'branch_itemtype' %]
1431
                                    [% SET branchcodes = [] %]
1432
1403
1433
                                    [% FOREACH h IN biblioloo.reserveloop %]
1404
                                    [% FOREACH b IN biblioloo.hold_branches %]
1434
                                        [% branchcodes.push( h.branchcode ) %]
1405
                                        <div class="holds_by_library">
1435
                                    [% END %]
1406
                                            <h4>[% Branches.GetName( b ) | html %]</h4>
1436
                                    [% branchcodes = branchcodes.unique %]
1407
                                            [% FOREACH i IN biblioloo.hold_itemtypes %]
1437
                                    [% IF ( branchcodes.empty ) %]
1408
                                                <div class="holds_by_itemtype">
1438
                                        <div class="alert alert-info"> There are no holds on this title. </div>
1409
                                                    [% IF i && i != 'any' %]
1439
                                    [% ELSE %]
1410
                                                        <h4>[% ItemTypes.GetDescription( i ) | html %]</h4>
1440
1411
                                                    [% ELSE %]
1441
                                        [% FOREACH b IN branchcodes.sort %]
1412
                                                        <h4>Any item type</h4>
1442
                                            <div class="holds_by_library">
1443
                                                <h4 class="library_holds">[% Branches.GetName( b ) | html %]</h4>
1444
                                                [% SET holds_by_branch = [] %]
1445
                                                [% FOREACH h IN biblioloo.reserveloop %]
1446
                                                    [% IF h.branchcode == b %]
1447
                                                        [% holds_by_branch.push( h ) %]
1448
                                                    [% END %]
1413
                                                    [% END %]
1449
                                                [% END %]
1414
                                                    [% SET split_data = b _ "_" _ i %]
1450
1415
                                                    [% INCLUDE holds_table.inc biblio_id=biblioloo.biblionumber total_holds=biblioloo.total_holds split_data=split_data %]
1451
                                                [% SET itemtypes = [] %]
1416
                                                </div>
1452
                                                [% FOREACH h IN holds_by_branch %]
1417
                                            [% END %]
1453
                                                    [% SET hold_itemtype = h.object.item.effective_itemtype || h.itemtype %]
1418
                                        </div>
1454
                                                    [% itemtypes.push( hold_itemtype ) %]
1455
                                                [% END %]
1456
                                                [% itemtypes = itemtypes.unique %]
1457
1458
                                                [% FOREACH i IN itemtypes.sort %]
1459
                                                    <div class="holds_by_itemtype">
1460
                                                        <h5 class="itemtype_holds">
1461
                                                            [% IF i %]
1462
                                                                [% ItemTypes.GetDescription( i ) | html %]
1463
                                                            [% ELSE %]
1464
                                                                <span>Any item type</span>
1465
                                                            [% END %]
1466
                                                        </h5>
1467
1468
                                                        [% SET holds_by_itemtype = [] %]
1469
                                                        [% FOREACH h IN holds_by_branch %]
1470
                                                            [% SET hold_itemtype = h.object.item.effective_itemtype || h.itemtype %]
1471
                                                            [% IF hold_itemtype == i %]
1472
                                                                [% holds_by_itemtype.push( h ) %]
1473
                                                            [% END %]
1474
                                                        [% END %]
1475
                                                        [% INCLUDE holds_table.inc holds=holds_by_itemtype %]
1476
                                                    </div>
1477
                                                    <!-- /.holds_by_itemtype -->
1478
                                                [% END %]
1479
                                            </div>
1480
                                            <!-- /.holds_by_library -->
1481
                                        [% END # /FOREACH b %]
1482
                                    [% END # /IF ( branchcodes.empty ) %]
1483
                                [% ELSE %]
1484
1485
                                    [% IF ( biblioloo.reserveloop.size ) %]
1486
                                        [% INCLUDE holds_table.inc holds=biblioloo.reserveloop %]
1487
                                    [% ELSE %]
1488
                                        <div class="alert alert-info"> There are no holds on this title. </div>
1489
                                    [% END %]
1419
                                    [% END %]
1420
                                [% ELSE %]
1421
                                    [% INCLUDE holds_table.inc biblio_id=biblioloo.biblionumber total_holds=biblioloo.total_holds split_data="any" %]
1490
                                [% END # /IF HoldsSplitQueue %]
1422
                                [% END # /IF HoldsSplitQueue %]
1491
                            </div>
1423
                            </div>
1492
                            <!-- /hold_title -->
1424
                            <!-- /hold_title -->
1493
                        [% END # /IF biblioloo.reserveloop %]
1425
                        [% ELSE %]
1426
                            <div class="note"> There are no holds on this title. </div>
1427
                        [% END # /IF ( biblioloo.total_holds ) %]
1494
                    [% END # FOREACH biblioloo %]
1428
                    [% END # FOREACH biblioloo %]
1495
                </div>
1429
                </div>
1496
            </form>
1430
            </form>
Lines 1605-1610 Link Here
1605
    [% INCLUDE 'datatables.inc' %]
1539
    [% INCLUDE 'datatables.inc' %]
1606
    [% INCLUDE 'calendar.inc' %]
1540
    [% INCLUDE 'calendar.inc' %]
1607
    [% INCLUDE 'select2.inc' %]
1541
    [% INCLUDE 'select2.inc' %]
1542
    <script>
1543
        hold_table_settings = [% TablesSettings.GetTableSettings( 'circ', 'holds', 'patron_holds_table', 'json' ) | $raw %];
1544
    </script>
1608
    [% Asset.js("js/holds.js") | $raw %]
1545
    [% Asset.js("js/holds.js") | $raw %]
1609
    [% Asset.js("js/hold-group.js") | $raw %]
1546
    [% Asset.js("js/hold-group.js") | $raw %]
1610
1547
Lines 1613-1629 Link Here
1613
        [% SET url_biblio_params = url_biblio_params _ "&amp;multi_hold=1" %]
1550
        [% SET url_biblio_params = url_biblio_params _ "&amp;multi_hold=1" %]
1614
    [% END %]
1551
    [% END %]
1615
    <script>
1552
    <script>
1616
        $(document).ready(function () {
1617
            hold_table_settings = [% TablesSettings.GetTableSettings( 'circ', 'holds', 'patron_holds_table', 'json' ) | $raw %];
1618
            $("#patron_holds_table").kohaTable(
1619
                {
1620
                    paging: false,
1621
                    bKohaColumnsUseNames: true,
1622
                },
1623
                hold_table_settings
1624
            );
1625
        });
1626
        var biblionumbers = [[% biblionumbers.join(', ') | $raw %]];
1553
        var biblionumbers = [[% biblionumbers.join(', ') | $raw %]];
1554
        var hold_branches = {[% FOREACH biblio_info IN biblioloop %] [% biblio_info.biblionumber | html %]: ["[% biblio_info.hold_branches.join('", "') | $raw %]"], [% END %]};
1555
        var hold_itemtypes = {[% FOREACH biblio_info IN biblioloop %] [% biblio_info.biblionumber | html %]: ["[% biblio_info.hold_itemtypes.join('", "') | $raw %]"], [% END %]};
1556
        var HoldsSplitQueue = "[% Koha.Preference('HoldsSplitQueue') | html %]";
1557
        var HoldsSplitQueueNumbering = "[% Koha.Preference('HoldsSplitQueueNumbering') | html %]";
1558
        var SuspendHoldsIntranet = [% ( Koha.Preference('SuspendHoldsIntranet') ) ? 1 : 0 | html %];
1559
        var AutoResumeSuspendedHolds = [% ( Koha.Preference('AutoResumeSuspendedHolds') ) ? 1 : 0 | html %];
1560
        var AllowHoldDateInFuture = [% ( Koha.Preference('AllowHoldDateInFuture') ) ? 1 : 0 | html %];
1561
        var HidePatronName = [% ( Koha.Preference('HidePatronName') ) ? 1 : 0 | html %];
1562
        var CAN_user_reserveforothers_modify_holds_priority = [%CAN_user_reserveforothers_modify_holds_priority ? 1 : 0 | html %];
1627
        var borrowernumber = "[% patron.borrowernumber | $raw %]";
1563
        var borrowernumber = "[% patron.borrowernumber | $raw %]";
1628
        var patron_homebranch = "[% To.json( Branches.GetName( patron.branchcode ) ) | $raw %]";
1564
        var patron_homebranch = "[% To.json( Branches.GetName( patron.branchcode ) ) | $raw %]";
1629
        var override_items = {[% FOREACH biblio_info IN biblioloop %][% FOREACH itemloo IN biblio_info.itemloop %][% IF ( itemloo.override ) %]
1565
        var override_items = {[% FOREACH biblio_info IN biblioloop %][% FOREACH itemloo IN biblio_info.itemloop %][% IF ( itemloo.override ) %]
Lines 1651-1656 Link Here
1651
        $.fn.select2.defaults.set("dropdownAutoWidth", true );
1587
        $.fn.select2.defaults.set("dropdownAutoWidth", true );
1652
1588
1653
        $(document).ready(function() {
1589
        $(document).ready(function() {
1590
            biblionumbers.forEach(function(biblionumber) {
1591
                let branches = hold_branches[biblionumber];
1592
                let itemtypes = hold_itemtypes[biblionumber];
1593
                switch (HoldsSplitQueue) {
1594
                    case 'branch':
1595
                        branches.forEach(function(branch) {
1596
                            load_patron_holds_table(biblionumber, {name: HoldsSplitQueue, value: branch});
1597
                        });
1598
                        break;
1599
                    case 'itemtype':
1600
                        itemtypes.forEach(function(itemtype) {
1601
                            load_patron_holds_table(biblionumber, {name: HoldsSplitQueue, value: itemtype});
1602
                        });
1603
                        break;
1604
                    case 'branch_itemtype':
1605
                        branches.forEach(function(branch) {
1606
                            itemtypes.forEach(function(itemtype) {
1607
                                load_patron_holds_table(biblionumber, {name: HoldsSplitQueue, value: branch + '_' + itemtype});
1608
                            });
1609
                        });
1610
                        break;
1611
                    default:
1612
                        load_patron_holds_table(biblionumber, {name: 'any', value: 'any'});
1613
                }
1614
            });
1654
            $('#cancellation-reason-div').hide();
1615
            $('#cancellation-reason-div').hide();
1655
            $('.rank-request').on('change', function() {
1616
            $('.rank-request').on('change', function() {
1656
                if ( $(".rank-request option:selected[value='del']").length ) {
1617
                if ( $(".rank-request option:selected[value='del']").length ) {
Lines 2011-2076 Link Here
2011
                });
1972
                });
2012
            [% END %]
1973
            [% END %]
2013
1974
2014
            $(".hold-arrow").click(function(e) {
1975
            if(!localStorage.selectedHolds  || document.referrer.replace(/\?.*/, '') !== document.location.origin+document.location.pathname) {
2015
                e.preventDefault();
1976
                localStorage.selectedHolds = [];
2016
                let arrowForm = $("#hold-actions-form").attr({
1977
            }
2017
                    action: 'request.pl',
1978
2018
                    method: 'post'
2019
                });
2020
                let arrow_op = $("<input />").attr({
2021
                    name: 'op',
2022
                    type: 'hidden',
2023
                    value: $(this).data('op')
2024
                });
2025
                let arrow_where = $("<input />").attr({
2026
                    name: 'where',
2027
                    type: 'hidden',
2028
                    value: $(this).data('where')
2029
                });
2030
                let arrow_fp = $("<input />").attr({
2031
                    name: 'first_priority',
2032
                    type: 'hidden',
2033
                    value: $(this).data('first_priority')
2034
                });
2035
                let arrow_lp = $("<input />").attr({
2036
                    name: 'last_priority',
2037
                    type: 'hidden',
2038
                    value: $(this).data('last_priority')
2039
                });
2040
                let arrow_pp = $("<input />").attr({
2041
                    name: 'prev_priority',
2042
                    type: 'hidden',
2043
                    value: $(this).data('prev_priority')
2044
                });
2045
                let arrow_np = $("<input />").attr({
2046
                    name: 'next_priority',
2047
                    type: 'hidden',
2048
                    value: $(this).data('next_priority')
2049
                });
2050
                let arrow_bn = $("<input />").attr({
2051
                    name: 'borrowernumber',
2052
                    type: 'hidden',
2053
                    value: $(this).data('borrowernumber')
2054
                });
2055
                let arrow_bb = $("<input />").attr({
2056
                    name: 'biblionumber',
2057
                    type: 'hidden',
2058
                    value: $(this).data('biblionumber')
2059
                });
2060
                let arrow_ri = $("<input />").attr({
2061
                    name: 'reserve_id',
2062
                    type: 'hidden',
2063
                    value: $(this).data('reserve_id')
2064
                });
2065
                let arrow_date = $("<input />").attr({
2066
                    name: 'date',
2067
                    type: 'hidden',
2068
                    value: $(this).data('date')
2069
                });
2070
                arrowForm.append(arrow_op,arrow_where,arrow_fp,arrow_lp,arrow_pp,arrow_np,arrow_bn,arrow_bb,arrow_ri,arrow_date);
2071
                $("#hold-actions-form").submit();
2072
                return true;
2073
            })
2074
        });
1979
        });
2075
    </script>
1980
    </script>
2076
    <script>
1981
    <script>
Lines 2086-2098 Link Here
2086
            });
1991
            });
2087
        </script>
1992
        </script>
2088
    [% END %]
1993
    [% END %]
2089
    <script>
2090
        $(".printholdslip").click(function () {
2091
            var reserve_id = $(this).attr("data-reserve_id");
2092
            window.open("/cgi-bin/koha/circ/hold-transfer-slip.pl?reserve_id=" + reserve_id);
2093
            return false;
2094
        });
2095
    </script>
2096
[% END %]
1994
[% END %]
2097
1995
2098
[% INCLUDE 'intranet-bottom.inc' %]
1996
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/koha-tmpl/intranet-tmpl/prog/js/datatables.js (+3 lines)
Lines 1456-1461 function update_search_description( Link Here
1456
                    emptyTable: options.emptyTable
1456
                    emptyTable: options.emptyTable
1457
                        ? options.emptyTable
1457
                        ? options.emptyTable
1458
                        : __("No data available in table"),
1458
                        : __("No data available in table"),
1459
                    infoFiltered: options.infoFiltered
1460
                        ? options.infoFiltered
1461
                        : __("(filtered from _MAX_ total entries)"),
1459
                },
1462
                },
1460
            },
1463
            },
1461
            options
1464
            options
(-)a/koha-tmpl/intranet-tmpl/prog/js/holds.js (-139 / +1224 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 1226-1237 $(document).ready(function () { Link Here
1226
            }),
1212
            }),
1227
        });
1213
        });
1228
    }
1214
    }
1229
1215
    if (holds_table_patron_page()) {
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) {
1234
    });
1220
                holdsTable.api().ajax.reload();
1221
            }
1222
        });
1223
    }
1235
1224
1236
    $("#group-modal-submit").click(function (e) {
1225
    $("#group-modal-submit").click(function (e) {
1237
        e.preventDefault();
1226
        e.preventDefault();
Lines 1303-1305 $(document).ready(function () { Link Here
1303
        );
1292
        );
1304
    }
1293
    }
1305
});
1294
});
1295
1296
async function load_patron_holds_table(biblio_id, split_data) {
1297
    const { name: split_name, value: split_value } = split_data;
1298
    let table_class = `patron_holds_table_${biblio_id}_${split_value}`;
1299
    const table_id = `#` + table_class;
1300
    let url = `/api/v1/holds/?q={"me.biblio_id":${biblio_id}`;
1301
1302
    if (split_name === "branch" && split_value !== "any") {
1303
        url += `, "me.pickup_library_id":"${split_value}"`;
1304
    } else if (split_name === "itemtype" && split_value !== "any") {
1305
        url += `, "me.itemtype":"${split_value}"`;
1306
    } else if (split_name === "branch_itemtype") {
1307
        const [branch, itemtype] = split_value.split("_");
1308
        url +=
1309
            itemtype === "any"
1310
                ? `, "me.pickup_library_id":"${branch}"`
1311
                : `, "me.pickup_library_id":"${branch}", "me.itemtype":"${itemtype}"`;
1312
    }
1313
1314
    url += "}";
1315
    const totalHolds = $(table_id).data("total-holds");
1316
    const totalHoldsSelect = parseInt(totalHolds) + 1;
1317
    var holdsQueueTable = $(table_id).kohaTable(
1318
        {
1319
            language: {
1320
                infoFiltered: "",
1321
            },
1322
            ajax: {
1323
                url: url,
1324
            },
1325
            embed: ["patron", "item", "item_group", "item_level_holds"],
1326
            columnDefs: [
1327
                {
1328
                    targets: [2, 3],
1329
                    className: "dt-body-nowrap",
1330
                },
1331
                {
1332
                    targets: [3, 9],
1333
                    visible: CAN_user_reserveforothers_modify_holds_priority
1334
                        ? true
1335
                        : false,
1336
                },
1337
            ],
1338
            columns: [
1339
                {
1340
                    data: "hold_id",
1341
                    orderable: false,
1342
                    searchable: false,
1343
                    render: function (data, type, row, meta) {
1344
                        return (
1345
                            '<input type="checkbox" class="select_hold ' +
1346
                            table_class +
1347
                            '" data-id="' +
1348
                            data +
1349
                            '" data-borrowernumber="' +
1350
                            row.patron_id +
1351
                            '" data-biblionumber="' +
1352
                            biblio_id +
1353
                            '" data-itemnumber="' +
1354
                            row.item_id +
1355
                            '" data-hold-group-id="' +
1356
                            row.hold_group_id +
1357
                            '" data-item_level_hold="' +
1358
                            row.item_level_holds +
1359
                            '" data-waiting="' +
1360
                            (row.status === "W" ? "1" : "") +
1361
                            '" data-intransit="' +
1362
                            (row.status === "T" ? "1" : "") +
1363
                            '" data-status="' +
1364
                            (row.status ? row.status : "") +
1365
                            '"/>'
1366
                        );
1367
                    },
1368
                },
1369
                {
1370
                    data: "priority",
1371
                    orderable: true,
1372
                    searchable: false,
1373
                    render: function (data, type, row, meta) {
1374
                        let select =
1375
                            '<select name="rank-request" class="rank-request ' +
1376
                            table_class +
1377
                            '" data-id="' +
1378
                            row.hold_id;
1379
                        if (
1380
                            CAN_user_reserveforothers_modify_holds_priority &&
1381
                            split_name == "any"
1382
                        ) {
1383
                            for (var i = 0; i < totalHoldsSelect; i++) {
1384
                                let selected;
1385
                                let value;
1386
                                let desc;
1387
                                if (data == i && row.status == "T") {
1388
                                    select += '" disabled="disabled">';
1389
                                    selected = " selected='selected' ";
1390
                                    value = "T";
1391
                                    desc = "In transit";
1392
                                } else if (data == i && row.status == "P") {
1393
                                    select += '" disabled="disabled">';
1394
                                    selected = " selected='selected' ";
1395
                                    value = "P";
1396
                                    desc = "In processing";
1397
                                } else if (data == i && row.status == "W") {
1398
                                    select += '" disabled="disabled">';
1399
                                    selected = " selected='selected' ";
1400
                                    value = "W";
1401
                                    desc = "Waiting";
1402
                                } else if (data == i && !row.status) {
1403
                                    select += '">';
1404
                                    selected = " selected='selected' ";
1405
                                    value = data;
1406
                                    desc = data;
1407
                                } else {
1408
                                    if (i != 0) {
1409
                                        select += '">';
1410
                                        value = i;
1411
                                        desc = i;
1412
                                    } else {
1413
                                        select += '">';
1414
                                    }
1415
                                }
1416
                                if (value) {
1417
                                    select +=
1418
                                        '<option value="' +
1419
                                        value +
1420
                                        '"' +
1421
                                        selected +
1422
                                        ">" +
1423
                                        desc +
1424
                                        "</option>";
1425
                                }
1426
                            }
1427
                        } else {
1428
                            if (row.status == "T") {
1429
                                select +=
1430
                                    '" disabled="disabled"><option value="T" selected="selected">In transit</option></select>';
1431
                            } else if (row.status == "P") {
1432
                                select +=
1433
                                    '" disabled="disabled"><option value="P" selected="selected">In processing</option></select>';
1434
                            } else if (row.status == "W") {
1435
                                select +=
1436
                                    '" disabled="disabled"><option value="W" selected="selected">Waiting</option></select>';
1437
                            } else {
1438
                                if (
1439
                                    HoldsSplitQueue !== "nothing" &&
1440
                                    HoldsSplitQueueNumbering === "virtual"
1441
                                ) {
1442
                                    let virtualPriority =
1443
                                        meta.settings._iDisplayStart +
1444
                                        meta.row +
1445
                                        1;
1446
                                    select +=
1447
                                        '" disabled="disabled"><option value="' +
1448
                                        data +
1449
                                        '" selected="selected">' +
1450
                                        virtualPriority +
1451
                                        "</option></select>";
1452
                                } else {
1453
                                    select +=
1454
                                        '" disabled="disabled"><option value="' +
1455
                                        data +
1456
                                        '" selected="selected">' +
1457
                                        data +
1458
                                        "</option></select>";
1459
                                }
1460
                            }
1461
                        }
1462
                        select += "</select>";
1463
                        return select;
1464
                    },
1465
                },
1466
                {
1467
                    data: "",
1468
                    orderable: false,
1469
                    searchable: false,
1470
                    render: function (data, type, row, meta) {
1471
                        if (row.status) {
1472
                            return null;
1473
                        }
1474
                        let buttons =
1475
                            '<a class="hold-arrow move-hold ' +
1476
                            table_class +
1477
                            '" title="Move hold up" href="#" data-move-hold="up" data-priority="' +
1478
                            row.priority +
1479
                            '" reserve_id="' +
1480
                            row.hold_id +
1481
                            '"><i class="fa fa-lg icon-move-hold-up" aria-hidden="true"></i></a>';
1482
                        buttons +=
1483
                            '<a class="hold-arrow move-hold ' +
1484
                            table_class +
1485
                            '" title="Move hold to top" href="#" data-move-hold="top" data-priority="' +
1486
                            row.priority +
1487
                            '" reserve_id="' +
1488
                            row.hold_id +
1489
                            '"><i class="fa fa-lg icon-move-hold-top" aria-hidden="true"></i></a>';
1490
                        buttons +=
1491
                            '<a class="hold-arrow move-hold ' +
1492
                            table_class +
1493
                            '" title="Move hold to bottom" href="#" data-move-hold="bottom" data-priority="' +
1494
                            row.priority +
1495
                            '" reserve_id="' +
1496
                            row.hold_id +
1497
                            '"><i class="fa fa-lg icon-move-hold-bottom" aria-hidden="true"></i></a>';
1498
                        buttons +=
1499
                            '<a class="hold-arrow move-hold ' +
1500
                            table_class +
1501
                            '" title="Move hold down" href="#" data-move-hold="down" data-priority="' +
1502
                            row.priority +
1503
                            '" reserve_id="' +
1504
                            row.hold_id +
1505
                            '"><i class="fa fa-lg icon-move-hold-down" aria-hidden="true"></i></a>';
1506
                        return buttons;
1507
                    },
1508
                },
1509
                {
1510
                    data: "patron.cardnumber",
1511
                    orderable: true,
1512
                    searchable: true,
1513
                    render: function (data, type, row, meta) {
1514
                        if (data == null) {
1515
                            let library = libraries.find(
1516
                                library => library._id == row.pickup_library_id
1517
                            );
1518
                            return __("A patron from library %s").format(
1519
                                library.name
1520
                            );
1521
                        } else {
1522
                            return (
1523
                                '<a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=' +
1524
                                row.patron.patron_id +
1525
                                '">' +
1526
                                data +
1527
                                "</a>"
1528
                            );
1529
                        }
1530
                    },
1531
                },
1532
                {
1533
                    data: "notes",
1534
                    orderable: false,
1535
                    searchable: false,
1536
                    render: function (data, type, row, meta) {
1537
                        return data;
1538
                    },
1539
                },
1540
                {
1541
                    data: "hold_date",
1542
                    orderable: true,
1543
                    searchable: false,
1544
                    render: function (data, type, row, meta) {
1545
                        if (AllowHoldDateInFuture) {
1546
                            return (
1547
                                '<input type="text" class="holddate ' +
1548
                                table_class +
1549
                                '" value="' +
1550
                                $date(data, { dateformat: "rfc3339" }) +
1551
                                '" size="10" name="hold_date" data-id="' +
1552
                                row.hold_id +
1553
                                '" data-current-date="' +
1554
                                data +
1555
                                '"/>'
1556
                            );
1557
                        } else {
1558
                            return $date(data);
1559
                        }
1560
                    },
1561
                },
1562
                {
1563
                    data: "expiration_date",
1564
                    orderable: true,
1565
                    searchable: false,
1566
                    render: function (data, type, row, meta) {
1567
                        return (
1568
                            '<input type="text" class="expirationdate ' +
1569
                            table_class +
1570
                            '" value="' +
1571
                            $date(data, { dateformat: "rfc3339" }) +
1572
                            '" size="10" name="expiration_date" data-id="' +
1573
                            row.hold_id +
1574
                            '" data-current-date="' +
1575
                            data +
1576
                            '"/>'
1577
                        );
1578
                    },
1579
                },
1580
                {
1581
                    data: "pickup_library_id",
1582
                    orderable: true,
1583
                    searchable: false,
1584
                    render: function (data, type, row, meta) {
1585
                        var branchSelect =
1586
                            "<select priority=" +
1587
                            row.priority +
1588
                            ' class="hold_location_select ' +
1589
                            table_class +
1590
                            '" data-id="' +
1591
                            row.hold_id +
1592
                            '" reserve_id="' +
1593
                            row.hold_id +
1594
                            '" name="pick-location" data-pickup-location-source="hold">';
1595
                        var libraryname;
1596
                        for (var i = 0; i < libraries.length; i++) {
1597
                            var selectedbranch;
1598
                            var setbranch;
1599
                            if (libraries[i]._id == data) {
1600
                                selectedbranch = " selected='selected' ";
1601
                                setbranch = __(" (current) ");
1602
                                libraryname = libraries[i]._str;
1603
                            } else if (libraries[i].pickup_location == false) {
1604
                                continue;
1605
                            } else {
1606
                                selectedbranch = "";
1607
                                setbranch = "";
1608
                            }
1609
                            branchSelect +=
1610
                                '<option value="' +
1611
                                libraries[i]._id.escapeHtml() +
1612
                                '"' +
1613
                                selectedbranch +
1614
                                ">" +
1615
                                libraries[i]._str.escapeHtml() +
1616
                                setbranch +
1617
                                "</option>";
1618
                        }
1619
                        branchSelect += "</select>";
1620
                        if (row.status == "T") {
1621
                            return __(
1622
                                "Item being transferred to <strong>%s</strong>"
1623
                            ).format(libraryname);
1624
                        } else if (row.status == "P") {
1625
                            return __(
1626
                                "Item being processed at <strong>%s</strong>"
1627
                            ).format(libraryname);
1628
                        } else if (row.status == "W") {
1629
                            return __(
1630
                                "Item waiting at <strong>%s</strong> since %s"
1631
                            ).format(libraryname, $date(row.waiting_date));
1632
                        } else {
1633
                            return branchSelect;
1634
                        }
1635
                    },
1636
                },
1637
                {
1638
                    data: "",
1639
                    orderable: false,
1640
                    searchable: false,
1641
                    render: function (data, type, row, meta) {
1642
                        if (row.status) {
1643
                            return (
1644
                                '<a href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=' +
1645
                                row.biblio_id +
1646
                                "&itemnumber=" +
1647
                                row.item_id +
1648
                                '">' +
1649
                                row.item.external_id +
1650
                                "</a>"
1651
                            );
1652
                        } else if (row.item_id && row.item_level) {
1653
                            let barcode = row.item.external_id
1654
                                ? row.item.external_id
1655
                                : __("No barcode");
1656
                            if (row.item_level_holds >= 2) {
1657
                                let link =
1658
                                    '<a href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=' +
1659
                                    row.biblio_id +
1660
                                    "&itemnumber=" +
1661
                                    row.item_id +
1662
                                    '">' +
1663
                                    (row.item.external_id
1664
                                        ? row.item.external_id.escapeHtml()
1665
                                        : __("No barcode")) +
1666
                                    "</a>";
1667
                                return __("Only item") + " " + link;
1668
                            } else {
1669
                                let select =
1670
                                    '<select id="change_hold_type" class="change_hold_type ' +
1671
                                    table_class +
1672
                                    '" data-id="' +
1673
                                    row.hold_id +
1674
                                    '">';
1675
                                select +=
1676
                                    '<option value="" selected>' +
1677
                                    __("Only item") +
1678
                                    " " +
1679
                                    barcode +
1680
                                    "</option>";
1681
                                select +=
1682
                                    '<option value="">' +
1683
                                    __("Next available") +
1684
                                    "</option>";
1685
                                select += "</select>";
1686
                                return select;
1687
                            }
1688
                        } else if (row.item_group_id) {
1689
                            return __(
1690
                                "Next available item from group <strong>%s</strong>"
1691
                            ).format(row.item_group.description);
1692
                        } else if (row.hold_group_id) {
1693
                            return (
1694
                                "<div>(" +
1695
                                __("part of") +
1696
                                ' <a href="/cgi-bin/koha/reserve/hold-group.pl?hold_group_id=' +
1697
                                row.hold_group_id +
1698
                                '" class="hold-group">' +
1699
                                __("hold group") +
1700
                                "</a>)</div>"
1701
                            );
1702
                        } else {
1703
                            if (row.non_priority) {
1704
                                return (
1705
                                    "<em>" +
1706
                                    __("Next available") +
1707
                                    "</em><br/><i>" +
1708
                                    __("Non priority hold") +
1709
                                    "</i>"
1710
                                );
1711
                            } else {
1712
                                return "<em>" + __("Next available") + "</em>";
1713
                            }
1714
                        }
1715
                    },
1716
                },
1717
                {
1718
                    data: "",
1719
                    orderable: false,
1720
                    searchable: false,
1721
                    render: function (data, type, row, meta) {
1722
                        if (row.item_id) {
1723
                            return null;
1724
                        } else {
1725
                            if (row.lowest_priority) {
1726
                                return (
1727
                                    '<a class="hold-arrow toggle-lowest-priority ' +
1728
                                    table_class +
1729
                                    '" title="Remove lowest priority" href="#" data-op="cud-setLowestPriority" data-borrowernumber="' +
1730
                                    row.patron_id +
1731
                                    '" data-biblionumber="' +
1732
                                    biblio_id +
1733
                                    '" data-reserve_id="' +
1734
                                    row.hold_id +
1735
                                    '" data-date="' +
1736
                                    row.hold_date +
1737
                                    '"><i class="fa fa-lg fa-rotate-90 icon-unset-lowest" aria-hidden="true"></i></a>'
1738
                                );
1739
                            } else {
1740
                                return (
1741
                                    '<a class="hold-arrow toggle-lowest-priority ' +
1742
                                    table_class +
1743
                                    '" title="Set lowest priority" href="#" data-op="cud-setLowestPriority" data-borrowernumber="' +
1744
                                    row.patron_id +
1745
                                    '" data-biblionumber="' +
1746
                                    biblio_id +
1747
                                    '" data-reserve_id="' +
1748
                                    row.hold_id +
1749
                                    '" data-date="' +
1750
                                    row.hold_date +
1751
                                    '"><i class="fa fa-lg fa-rotate-90 icon-set-lowest" aria-hidden="true"></i></a>'
1752
                                );
1753
                            }
1754
                        }
1755
                    },
1756
                },
1757
                {
1758
                    data: "hold_id",
1759
                    orderable: false,
1760
                    searchable: false,
1761
                    render: function (data, type, row, meta) {
1762
                        return (
1763
                            '<a class="cancel-hold deny ' +
1764
                            table_class +
1765
                            '" title="Cancel hold" data-id="' +
1766
                            data +
1767
                            '" data-biblionumber="' +
1768
                            biblio_id +
1769
                            '" data-borrowernumber="' +
1770
                            row.patron_id +
1771
                            '" href="#"><i class="fa fa-trash" aria-label="Cancel hold"></i></a>'
1772
                        );
1773
                    },
1774
                },
1775
                {
1776
                    data: "hold_id",
1777
                    orderable: false,
1778
                    searchable: false,
1779
                    render: function (data, type, row, meta) {
1780
                        if (row.status) {
1781
                            var link_value =
1782
                                row.status == "T"
1783
                                    ? __("Revert transit status")
1784
                                    : __("Revert waiting status");
1785
                            return (
1786
                                '<a class="btn btn-default submit-form-link" href="#" id="revert_hold_' +
1787
                                data +
1788
                                '" data-op="cud-move" data-where="down" data-first_priority="1" data-last_priority="' +
1789
                                totalHolds +
1790
                                '" data-prev_priority="0" data-next_priority="1" data-borrowernumber="' +
1791
                                row.patron_id +
1792
                                '" data-biblionumber="' +
1793
                                biblio_id +
1794
                                '" data-itemnumber="' +
1795
                                row.item_id +
1796
                                '" data-reserve_id="' +
1797
                                row.hold_id +
1798
                                '" data-date="' +
1799
                                row.hold_date +
1800
                                '" data-action="request.pl" data-method="post">' +
1801
                                link_value +
1802
                                "</a>"
1803
                            );
1804
                        } else {
1805
                            let td = "";
1806
                            if (SuspendHoldsIntranet) {
1807
                                td +=
1808
                                    '<button class="btn btn-default btn-xs toggle-suspend ' +
1809
                                    table_class +
1810
                                    '" data-id="' +
1811
                                    data +
1812
                                    '" data-biblionumber="' +
1813
                                    biblio_id +
1814
                                    '" data-suspended="' +
1815
                                    row.suspended +
1816
                                    '">';
1817
                                if (row.suspended) {
1818
                                    td +=
1819
                                        '<i class="fa fa-play" aria-hidden="true"></i> ' +
1820
                                        __("Unsuspend") +
1821
                                        "</button>";
1822
                                } else {
1823
                                    td +=
1824
                                        '<i class="fa fa-pause" aria-hidden="true"></i> ' +
1825
                                        __("Suspend") +
1826
                                        "</button>";
1827
                                }
1828
                                if (AutoResumeSuspendedHolds) {
1829
                                    if (row.suspended) {
1830
                                        td +=
1831
                                            '<label for="suspend_until_' +
1832
                                            data +
1833
                                            '">' +
1834
                                            __("Suspend on") +
1835
                                            " </label>";
1836
                                    } else {
1837
                                        td +=
1838
                                            '<label for="suspend_until_' +
1839
                                            data +
1840
                                            '">' +
1841
                                            __("Suspend until") +
1842
                                            " </label>";
1843
                                    }
1844
                                    td +=
1845
                                        '<input type="text" name="suspend_until_' +
1846
                                        data +
1847
                                        '" data-id="' +
1848
                                        data +
1849
                                        '" size="10" value="' +
1850
                                        $date(row.suspended_until, {
1851
                                            dateformat: "rfc3339",
1852
                                        }) +
1853
                                        '" class="suspenddate ' +
1854
                                        table_class +
1855
                                        '" data-flatpickr-futuredate="true" data-suspend-date="' +
1856
                                        row.suspended_until +
1857
                                        '" />';
1858
                                }
1859
                                return td;
1860
                            } else {
1861
                                return null;
1862
                            }
1863
                        }
1864
                    },
1865
                },
1866
                {
1867
                    data: "hold_id",
1868
                    orderable: false,
1869
                    searchable: false,
1870
                    render: function (data, type, row, meta) {
1871
                        if (row.status == "W" || row.status == "T") {
1872
                            return (
1873
                                '<a class="btn btn-default btn-xs printholdslip ' +
1874
                                table_class +
1875
                                '" data-reserve_id="' +
1876
                                data +
1877
                                '">' +
1878
                                __("Print slip") +
1879
                                "</a>"
1880
                            );
1881
                        } else {
1882
                            return "";
1883
                        }
1884
                    },
1885
                },
1886
            ],
1887
        },
1888
        hold_table_settings
1889
    );
1890
    holdsQueueTable.api().page(0).draw(false);
1891
    // Clear selectedHolds on page load
1892
    localStorage.removeItem("selectedHolds");
1893
    $(table_id).on("draw.dt", function () {
1894
        function updateMSGCounters() {
1895
            var MSG_CANCEL_SELECTED = __("Cancel selected (%s)");
1896
            var MSG_MOVE_SELECTED = __("Move selected (%s)");
1897
            var MSG_CANCEL_ALERT = __(
1898
                "This action will cancel <span class='badge bg-danger'>%s</span> hold(s)."
1899
            );
1900
            var selectedCount = JSON.parse(
1901
                localStorage.selectedHolds || "[]"
1902
            ).length;
1903
            $(".cancel_selected_holds").html(
1904
                MSG_CANCEL_SELECTED.format(selectedCount)
1905
            );
1906
            $(".move_selected_holds").html(
1907
                MSG_MOVE_SELECTED.format(selectedCount)
1908
            );
1909
            $("#cancel_hold_alert").html(
1910
                MSG_CANCEL_ALERT.format(selectedCount)
1911
            );
1912
            if (selectedCount > 0) {
1913
                $("#cancel_hold_alert").show();
1914
            } else {
1915
                $("#cancel_hold_alert").hide();
1916
            }
1917
        }
1918
1919
        function updateMoveButtons() {
1920
            var checked_holds = JSON.parse(localStorage.selectedHolds || "[]");
1921
            var checked_count = checked_holds.length;
1922
1923
            var item_level_count = checked_holds.filter(function (hold) {
1924
                return hold.item_level_hold > 0;
1925
            }).length;
1926
1927
            var record_level_count = checked_holds.filter(function (hold) {
1928
                return hold.item_level_hold === 0;
1929
            }).length;
1930
1931
            $(".move_hold_item").toggleClass("disabled", item_level_count <= 0);
1932
            $(".move_hold_biblio").toggleClass(
1933
                "disabled",
1934
                record_level_count <= 0
1935
            );
1936
            $(".move_selected_holds").prop("disabled", !checked_count);
1937
        }
1938
1939
        // Always deselect the "select all" checkbox when the page changes
1940
        $(".holds_table .select_hold_all").prop("checked", false);
1941
        updateMSGCounters();
1942
        $(".holds_table .select_hold." + table_class).each(function () {
1943
            const selected = JSON.parse(localStorage.selectedHolds || "[]");
1944
            const holdId = $(this).data("id");
1945
            if (selected.some(s => s.hold === holdId)) {
1946
                $(this).prop("checked", true);
1947
                $(this).parent().parent().addClass("selected");
1948
                var table = $(this).closest(".holds_table");
1949
                var count = $(
1950
                    ".select_hold." + table_class + ":not(:checked)",
1951
                    table
1952
                ).length;
1953
                $(".select_hold_all." + table_class, table).prop(
1954
                    "checked",
1955
                    !count
1956
                );
1957
            }
1958
        });
1959
        $(".holds_table .select_hold_all").on("click", function () {
1960
            var table = $(this).closest(".holds_table");
1961
            var isChecked = $(this).prop("checked");
1962
            var allCheckboxes = table
1963
                .DataTable()
1964
                .rows({ search: "applied" })
1965
                .nodes();
1966
            let selected = JSON.parse(localStorage.selectedHolds || "[]");
1967
            let pageHolds = [];
1968
1969
            $("input.select_hold", allCheckboxes).each(function () {
1970
                let hold_data = {
1971
                    hold: $(this).data("id"),
1972
                    borrowernumber: $(this).data("borrowernumber"),
1973
                    biblionumber: $(this).data("biblionumber"),
1974
                    itemnumber: $(this).data("itemnumber"),
1975
                    waiting: $(this).data("waiting"),
1976
                    intransit: $(this).data("intransit"),
1977
                    status: $(this).data("status"),
1978
                    item_level_hold: $(this).data("item_level_hold"),
1979
                    hold_group_id: $(this).data("hold-group-id"),
1980
                };
1981
                pageHolds.push(hold_data);
1982
            });
1983
1984
            if (isChecked) {
1985
                // Add all page holds to the selection, avoiding duplicates
1986
                pageHolds.forEach(hold => {
1987
                    if (!selected.some(s => s.hold === hold.hold)) {
1988
                        selected.push(hold);
1989
                    }
1990
                });
1991
                $("input.select_hold", allCheckboxes).prop("checked", true);
1992
                $("input.select_hold", allCheckboxes).each(function () {
1993
                    $(this).parent().parent().addClass("selected");
1994
                });
1995
            } else {
1996
                // Remove all page holds from the selection
1997
                const pageIds = pageHolds.map(h => h.hold);
1998
                selected = selected.filter(s => !pageIds.includes(s.hold));
1999
                $("input.select_hold", allCheckboxes).prop("checked", false);
2000
                $("input.select_hold", allCheckboxes).each(function () {
2001
                    $(this).parent().parent().removeClass("selected");
2002
                });
2003
            }
2004
2005
            localStorage.selectedHolds = JSON.stringify(selected);
2006
            updateMoveButtons();
2007
            updateMSGCounters();
2008
        });
2009
        $(".holds_table .select_hold").on("click", function () {
2010
            let selected = JSON.parse(localStorage.selectedHolds || "[]");
2011
            const hold_data = {
2012
                hold: $(this).data("id"),
2013
                borrowernumber: $(this).data("borrowernumber"),
2014
                biblionumber: $(this).data("biblionumber"),
2015
                itemnumber: $(this).data("itemnumber"),
2016
                waiting: $(this).data("waiting"),
2017
                intransit: $(this).data("intransit"),
2018
                status: $(this).data("status"),
2019
                item_level_hold: $(this).data("item_level_hold"),
2020
                hold_group_id: $(this).data("hold-group-id"),
2021
            };
2022
            if ($(this).is(":checked")) {
2023
                if (!selected.some(s => s.hold === hold_data.hold)) {
2024
                    selected.push(hold_data);
2025
                }
2026
            } else {
2027
                selected = selected.filter(s => s.hold !== hold_data.hold);
2028
            }
2029
            localStorage.selectedHolds = JSON.stringify(selected);
2030
            updateMoveButtons();
2031
            updateMSGCounters();
2032
            var table = $(this).parents(".holds_table");
2033
            var count = $(".select_hold:not(:checked)", table).length;
2034
            $(".select_hold_all", table).prop("checked", !count);
2035
            $(this).parent().parent().toggleClass("selected");
2036
        });
2037
        $(".cancel-hold." + table_class).on("click", function (e) {
2038
            e.preventDefault;
2039
            cancel_link = $(this);
2040
            $("#cancel_modal_form #inputs").empty();
2041
            let reserve_id = cancel_link.data("id");
2042
            let biblionumber = cancel_link.data("biblionumber");
2043
            _append_patron_page_cancel_hold_modal_data({
2044
                hold: reserve_id,
2045
                biblionumber: biblionumber,
2046
                borrowernumber: cancel_link.data("borrowernumber"),
2047
            });
2048
            $("#cancelModal").modal("show");
2049
        });
2050
        $(".cancel_selected_holds").click(function (e) {
2051
            e.preventDefault();
2052
            const selectedHolds = JSON.parse(
2053
                localStorage.selectedHolds || "[]"
2054
            );
2055
            if (selectedHolds.length) {
2056
                $("#cancel_modal_form #inputs").empty();
2057
2058
                selectedHolds.forEach(function (hold) {
2059
                    _append_patron_page_cancel_hold_modal_data(hold);
2060
                });
2061
2062
                //delete localStorage.selectedHolds;
2063
                $("#cancelModal").modal("show");
2064
            }
2065
            return false;
2066
        });
2067
        function _append_patron_page_cancel_hold_modal_data(hold) {
2068
            $("#cancel_modal_form #inputs").append(
2069
                '<input type="hidden" name="rank-request" value="del">'
2070
            );
2071
            $("#cancel_modal_form #inputs").append(
2072
                '<input type="hidden" name="biblionumber" value="' +
2073
                    hold.biblionumber +
2074
                    '">'
2075
            );
2076
            $("#cancel_modal_form #inputs").append(
2077
                '<input type="hidden" name="borrowernumber" value="' +
2078
                    hold.borrowernumber +
2079
                    '">'
2080
            );
2081
            $("#cancel_modal_form #inputs").append(
2082
                '<input type="hidden" name="reserve_id" value="' +
2083
                    hold.hold +
2084
                    '">'
2085
            );
2086
        }
2087
        // Remove any previously attached handlers
2088
        $("#cancelModalConfirmBtn").off("click");
2089
        // Attach the handler to the button
2090
        $("#cancelModalConfirmBtn").one("click", function (e) {
2091
            e.preventDefault();
2092
            let formInputs = {};
2093
            formInputs["reserve_id"] = $(
2094
                "#cancel_modal_form :input[name='reserve_id']"
2095
            )
2096
                .map(function () {
2097
                    return $(this).val();
2098
                })
2099
                .get();
2100
            formInputs["cancellation-reason"] = $(
2101
                "#cancel_modal_form :input[name='cancellation-reason']"
2102
            ).val();
2103
            cancel_holds(
2104
                formInputs["reserve_id"],
2105
                formInputs["cancellation-reason"]
2106
            )
2107
                .success(function () {
2108
                    holdsQueueTable.api().ajax.reload(null, false);
2109
                })
2110
                .fail(function (jqXHR) {
2111
                    $("#cancelModal .modal-body").prepend(
2112
                        '<div class="alert alert-danger">' +
2113
                            jqXHR.responseJSON.error +
2114
                            "</div>"
2115
                    );
2116
                    $("#cancelModalConfirmBtn").prop("disabled", true);
2117
                })
2118
                .done(function () {
2119
                    $("#cancelModal").modal("hide");
2120
                    if ($(".select_hold_all").prop("checked")) {
2121
                        $(".select_hold_all").click();
2122
                    }
2123
                });
2124
        });
2125
        function cancel_holds(hold_ids, cancellation_reason) {
2126
            return $.ajax({
2127
                method: "DELETE",
2128
                url: "/api/v1/holds/cancellation_bulk",
2129
                contentType: "application/json",
2130
                data: JSON.stringify({
2131
                    hold_ids: hold_ids,
2132
                    cancellation_reason: cancellation_reason,
2133
                }),
2134
            });
2135
        }
2136
        $(
2137
            ".holddate." + table_class + ", .expirationdate." + table_class
2138
        ).flatpickr({
2139
            onReady: function (selectedDates, dateStr, instance) {
2140
                $(instance.altInput)
2141
                    .wrap("<span class='flatpickr_wrapper'></span>")
2142
                    .after(
2143
                        $("<a/>")
2144
                            .attr("href", "#")
2145
                            .addClass("clear_date")
2146
                            .addClass("fa fa-times")
2147
                            .addClass("ps-2")
2148
                            .on("click", function (e) {
2149
                                e.preventDefault();
2150
                                instance.clear();
2151
                            })
2152
                            .attr("aria-hidden", true)
2153
                    );
2154
            },
2155
            onChange: function (selectedDates, dateStr, instance) {
2156
                let hold_id = $(instance.input).attr("data-id");
2157
                let fieldname = $(instance.input).attr("name");
2158
                let current_date = $(instance.input).attr("data-current-date");
2159
                dateStr = dateStr ? dateStr : null;
2160
                let req =
2161
                    fieldname == "hold_date"
2162
                        ? { hold_date: dateStr }
2163
                        : { expiration_date: dateStr };
2164
                if (current_date != dateStr) {
2165
                    $.ajax({
2166
                        method: "PATCH",
2167
                        url: "/api/v1/holds/" + encodeURIComponent(hold_id),
2168
                        contentType: "application/json",
2169
                        data: JSON.stringify(req),
2170
                        success: function (data) {
2171
                            holdsQueueTable.api().ajax.reload(null, false);
2172
                            $(instance.input).attr(
2173
                                "data-current-date",
2174
                                dateStr
2175
                            );
2176
                        },
2177
                        error: function (jqXHR, textStatus, errorThrown) {
2178
                            holdsQueueTable.api().ajax.reload(null, false);
2179
                        },
2180
                    });
2181
                }
2182
            },
2183
        });
2184
        $(".suspenddate." + table_class).flatpickr({
2185
            onReady: function (selectedDates, dateStr, instance) {
2186
                $(instance.altInput)
2187
                    .wrap("<span class='flatpickr_wrapper'></span>")
2188
                    .after(
2189
                        $("<a/>")
2190
                            .attr("href", "#")
2191
                            .addClass("clear_date")
2192
                            .addClass("fa fa-times")
2193
                            .addClass("ps-2")
2194
                            .on("click", function (e) {
2195
                                e.preventDefault();
2196
                                instance.clear();
2197
                            })
2198
                            .attr("aria-hidden", true)
2199
                    );
2200
            },
2201
        });
2202
        $(".toggle-suspend." + table_class).one("click", function (e) {
2203
            e.preventDefault();
2204
            const hold_id = $(this).data("id");
2205
            const suspended = $(this).attr("data-suspended");
2206
            const input = $(
2207
                `.suspenddate.` + table_class + `[data-id="${hold_id}"]`
2208
            );
2209
            const method = suspended == "true" ? "DELETE" : "POST";
2210
            let end_date = input.val() && method == "POST" ? input.val() : null;
2211
            let params =
2212
                end_date !== null && end_date !== ""
2213
                    ? JSON.stringify({ end_date: end_date })
2214
                    : null;
2215
            $.ajax({
2216
                method: method,
2217
                url:
2218
                    "/api/v1/holds/" +
2219
                    encodeURIComponent(hold_id) +
2220
                    "/suspension",
2221
                contentType: "application/json",
2222
                data: params,
2223
                success: function (data) {
2224
                    holdsQueueTable.api().ajax.reload(null, false);
2225
                },
2226
                error: function (jqXHR, textStatus, errorThrown) {
2227
                    holdsQueueTable.api().ajax.reload(null, false);
2228
                    alert(
2229
                        "There was an error:" + textStatus + " " + errorThrown
2230
                    );
2231
                },
2232
            });
2233
        });
2234
        $(".rank-request." + table_class).on("change", function (e) {
2235
            e.preventDefault();
2236
            const hold_id = $(this).data("id");
2237
            let priority = e.target.value;
2238
            // Replace select with spinner
2239
            const $select = $(this);
2240
            const $spinner = $(
2241
                '<img class="rank-spinner" src="/intranet-tmpl/prog/img/spinner-small.gif" alt="Loading..." style="display:block;margin:0 auto;vertical-align:middle;">'
2242
            );
2243
            $select.hide().after($spinner);
2244
            $.ajax({
2245
                method: "PUT",
2246
                url:
2247
                    "/api/v1/holds/" +
2248
                    encodeURIComponent(hold_id) +
2249
                    "/priority",
2250
                data: JSON.stringify(priority),
2251
                success: function (data) {
2252
                    holdsQueueTable.api().ajax.reload(null, false);
2253
                    $spinner.remove();
2254
                },
2255
                error: function (jqXHR, textStatus, errorThrown) {
2256
                    alert(
2257
                        "There was an error:" + textStatus + " " + errorThrown
2258
                    );
2259
                    $select.show();
2260
                    $spinner.remove();
2261
                },
2262
            });
2263
        });
2264
        $(".move-hold." + table_class).one("click", function (e) {
2265
            e.preventDefault();
2266
            let toPosition = $(this).attr("data-move-hold");
2267
            let priority = $(this).attr("data-priority");
2268
            var res_id = $(this).attr("reserve_id");
2269
            var moveTo;
2270
            if (toPosition == "up") {
2271
                moveTo = parseInt(priority) - 1;
2272
            }
2273
            if (toPosition == "down") {
2274
                moveTo = parseInt(priority) + 1;
2275
            }
2276
            if (toPosition == "top") {
2277
                moveTo = 1;
2278
            }
2279
            if (toPosition == "bottom") {
2280
                moveTo = totalHolds;
2281
            }
2282
            $.ajax({
2283
                method: "PUT",
2284
                url:
2285
                    "/api/v1/holds/" + encodeURIComponent(res_id) + "/priority",
2286
                data: JSON.stringify(moveTo),
2287
                success: function (data) {
2288
                    holdsQueueTable.api().ajax.reload(null, false);
2289
                },
2290
                error: function (jqXHR, textStatus, errorThrown) {
2291
                    alert(
2292
                        "There was an error:" + textStatus + " " + errorThrown
2293
                    );
2294
                },
2295
            });
2296
        });
2297
        $(".toggle-lowest-priority." + table_class).one("click", function (e) {
2298
            e.preventDefault();
2299
            var res_id = $(this).attr("data-reserve_id");
2300
            $.ajax({
2301
                method: "PUT",
2302
                url:
2303
                    "/api/v1/holds/" +
2304
                    encodeURIComponent(res_id) +
2305
                    "/lowest_priority",
2306
                success: function (data) {
2307
                    holdsQueueTable.api().ajax.reload(null, false);
2308
                },
2309
                error: function (jqXHR, textStatus, errorThrown) {
2310
                    alert(
2311
                        "There was an error:" + textStatus + " " + errorThrown
2312
                    );
2313
                },
2314
            });
2315
        });
2316
        $(".hold_location_select." + table_class).on("change", function () {
2317
            $(this).prop("disabled", true);
2318
            var cur_select = $(this);
2319
            var res_id = $(this).attr("reserve_id");
2320
            $(this).after(
2321
                '<div id="updating_reserveno' +
2322
                    res_id +
2323
                    '" class="waiting"><img src="/intranet-tmpl/prog/img/spinner-small.gif" alt="" /><span class="waiting_msg"></span></div>'
2324
            );
2325
            let api_url =
2326
                "/api/v1/holds/" +
2327
                encodeURIComponent(res_id) +
2328
                "/pickup_location";
2329
            $.ajax({
2330
                method: "PUT",
2331
                url: api_url,
2332
                data: JSON.stringify({ pickup_library_id: $(this).val() }),
2333
                headers: { "x-koha-override": "any" },
2334
                success: function (data) {
2335
                    holdsQueueTable.api().ajax.reload(null, false);
2336
                },
2337
                error: function (jqXHR, textStatus, errorThrown) {
2338
                    alert(
2339
                        "There was an error:" + textStatus + " " + errorThrown
2340
                    );
2341
                    cur_select.prop("disabled", false);
2342
                    $("#updating_reserveno" + res_id).remove();
2343
                    cur_select.val(
2344
                        cur_select.children('option[selected="selected"]').val()
2345
                    );
2346
                },
2347
            });
2348
        });
2349
        $(".change_hold_type." + table_class).on("change", function () {
2350
            $(this).prop("disabled", true);
2351
            var cur_select = $(this);
2352
            var hold_id = $(this).attr("data-id");
2353
            $(this).after(
2354
                '<div id="updating_holdno' +
2355
                    hold_id +
2356
                    '" class="waiting"><img src="/intranet-tmpl/prog/img/spinner-small.gif" alt="" /><span class="waiting_msg"></span></div>'
2357
            );
2358
            let api_url = "/api/v1/holds/" + encodeURIComponent(hold_id);
2359
            $.ajax({
2360
                method: "PATCH",
2361
                url: api_url,
2362
                data: JSON.stringify({ item_id: null, item_level: false }),
2363
                headers: { "x-koha-override": "any" },
2364
                contentType: "application/json",
2365
                success: function (data) {
2366
                    holdsQueueTable.api().ajax.reload(null, false);
2367
                },
2368
                error: function (jqXHR, textStatus, errorThrown) {
2369
                    alert(
2370
                        "There was an error:" + textStatus + " " + errorThrown
2371
                    );
2372
                    cur_select.prop("disabled", false);
2373
                    $("#updating_holdno" + hold_id).remove();
2374
                    cur_select.val(
2375
                        cur_select.children('option[selected="selected"]').val()
2376
                    );
2377
                },
2378
            });
2379
        });
2380
        $(".printholdslip." + table_class).one("click", function () {
2381
            var reserve_id = $(this).attr("data-reserve_id");
2382
            window.open(
2383
                "/cgi-bin/koha/circ/hold-transfer-slip.pl?reserve_id=" +
2384
                    reserve_id
2385
            );
2386
            return false;
2387
        });
2388
        updateMSGCounters();
2389
    });
2390
}
(-)a/reserve/request.pl (-62 / +33 lines)
Lines 669-677 if ( ( $findborrower && $borrowernumber_hold || $findclub && $club_hold ) Link Here
669
669
670
        # existingreserves building
670
        # existingreserves building
671
        my @reserveloop;
671
        my @reserveloop;
672
        my $total_holds       = 0;
673
        my $hold_branches     = [];
674
        my $hold_itemtypes    = [];
672
        my $always_show_holds = $input->cookie('always_show_holds');
675
        my $always_show_holds = $input->cookie('always_show_holds');
673
        $template->param( always_show_holds => $always_show_holds );
676
        $template->param( always_show_holds => $always_show_holds );
674
        my $show_holds_now = $input->param('show_holds_now');
677
        my $show_holds_now = $input->param('show_holds_now');
678
675
        unless ( ( defined $always_show_holds && $always_show_holds eq 'DONT' ) && !$show_holds_now ) {
679
        unless ( ( defined $always_show_holds && $always_show_holds eq 'DONT' ) && !$show_holds_now ) {
676
            my $holds_count_per_patron = {
680
            my $holds_count_per_patron = {
677
                map { $_->{borrowernumber} => $_->{hold_count} } @{ Koha::Holds->search(
681
                map { $_->{borrowernumber} => $_->{hold_count} } @{ Koha::Holds->search(
Lines 684-747 if ( ( $findborrower && $borrowernumber_hold || $findclub && $club_hold ) Link Here
684
                    )->unblessed
688
                    )->unblessed
685
                }
689
                }
686
            };
690
            };
687
            my @reserves = Koha::Holds->search(
691
            $total_holds = Koha::Holds->search( { biblionumber => $biblionumber } )->count;
688
                { 'me.biblionumber' => $biblionumber },
692
            my $branches = Koha::Holds->search(
689
                { prefetch          => [ 'borrowernumber', 'itemnumber' ], order_by => 'priority' }
693
                {
690
            )->as_list;
694
                    biblionumber => $biblionumber,
691
            foreach my $res (
695
                },
692
                sort {
696
                {
693
                    my $a_found = $a->found() || '';
697
                    select => [ { distinct => 'branchcode' } ],
694
                    my $b_found = $a->found() || '';
698
                    as     => [qw( branchcode )],
695
                    $a_found cmp $b_found;
696
                } @reserves
697
                )
698
            {
699
                my %reserve;
700
                if ( $res->is_found() ) {
701
                    $reserve{'holdingbranch'} = $res->item()->holdingbranch();
702
                    $reserve{'biblionumber'}  = $res->item()->biblionumber();
703
                    $reserve{'barcodenumber'} = $res->item()->barcode();
704
                    $reserve{'wbrcode'}       = $res->branchcode();
705
                    $reserve{'itemnumber'}    = $res->itemnumber();
706
                    $reserve{'wbrname'}       = $res->branch()->branchname();
707
                    $reserve{'atdestination'} = $res->is_at_destination();
708
                    $reserve{'desk_name'}     = ( $res->desk() ) ? $res->desk()->desk_name() : '';
709
                    $reserve{'found'}         = $res->is_found();
710
                    $reserve{'inprocessing'}  = $res->is_in_processing();
711
                    $reserve{'intransit'}     = $res->is_in_transit();
712
                } elsif ( $res->priority() > 0 ) {
713
                    if ( my $item = $res->item() ) {
714
                        $reserve{'itemnumber'}      = $item->id();
715
                        $reserve{'barcodenumber'}   = $item->barcode();
716
                        $reserve{'item_level_hold'} = 1;
717
                    }
718
                }
699
                }
719
                $reserve{'expirationdate'} = $res->expirationdate;
700
            )->unblessed;
720
                $reserve{'date'}           = $res->reservedate;
701
            $hold_branches = [ map { $_->{branchcode} } @$branches ];
721
                $reserve{'borrowernumber'} = $res->borrowernumber();
702
            my $itemtypes = Koha::Holds->search(
722
                $reserve{'biblionumber'}   = $res->biblionumber();
703
                {
723
                $reserve{'patron'}         = $res->borrower;
704
                    biblionumber => $biblionumber,
724
                $reserve{'notes'}          = $res->reservenotes();
705
                },
725
                $reserve{'waiting_date'}   = $res->waitingdate();
706
                {
726
                $reserve{'ccode'}          = $res->item() ? $res->item()->ccode()   : undef;
707
                    select => [ { distinct => 'itemtype' } ],
727
                $reserve{'barcode'}        = $res->item() ? $res->item()->barcode() : undef;
708
                    as     => [qw( itemtype )],
728
                $reserve{'priority'}       = $res->priority();
729
                $reserve{'lowestPriority'} = $res->lowestPriority();
730
                $reserve{'suspend'}        = $res->suspend();
731
                $reserve{'suspend_until'}  = $res->suspend_until();
732
                $reserve{'reserve_id'}     = $res->reserve_id();
733
                $reserve{itemtype}         = $res->itemtype();
734
                $reserve{branchcode}       = $res->branchcode();
735
                $reserve{non_priority}     = $res->non_priority();
736
                $reserve{object}           = $res;
737
                $reserve{hold_group_id}    = $res->hold_group_id;
738
739
                if ( $holds_count_per_patron->{ $reserve{'borrowernumber'} } == 1 ) {
740
                    $reserve{'change_hold_type_allowed'} = 1;
741
                }
709
                }
742
710
            )->unblessed;
743
                push( @reserveloop, \%reserve );
711
            $hold_itemtypes = [ map { $_->{itemtype} ? $_->{itemtype} : 'any' } @$itemtypes ];
744
            }
745
        }
712
        }
746
713
747
        # get the time for the form name...
714
        # get the time for the form name...
Lines 764-774 if ( ( $findborrower && $borrowernumber_hold || $findclub && $club_hold ) Link Here
764
            C4::Search::enabled_staff_search_views,
731
            C4::Search::enabled_staff_search_views,
765
        );
732
        );
766
733
767
        $biblioloopiter{biblionumber} = $biblionumber;
734
        $biblioloopiter{biblionumber}   = $biblionumber;
768
        $biblioloopiter{title}        = $biblio->title;
735
        $biblioloopiter{title}          = $biblio->title;
769
        $biblioloopiter{author}       = $biblio->author;
736
        $biblioloopiter{author}         = $biblio->author;
770
        $biblioloopiter{rank}         = $fixedRank;
737
        $biblioloopiter{rank}           = $fixedRank;
771
        $biblioloopiter{reserveloop}  = \@reserveloop;
738
        $biblioloopiter{reserveloop}    = \@reserveloop;
739
        $biblioloopiter{total_holds}    = $total_holds;
740
        $biblioloopiter{hold_branches}  = $hold_branches;
741
        $biblioloopiter{hold_itemtypes} = $hold_itemtypes;
772
742
773
        # Pass through any reserve charge
743
        # Pass through any reserve charge
774
        if ($patron) {
744
        if ($patron) {
Lines 791-796 if ( ( $findborrower && $borrowernumber_hold || $findclub && $club_hold ) Link Here
791
            $template->param( reserveloop => \@reserveloop );
761
            $template->param( reserveloop => \@reserveloop );
792
        }
762
        }
793
763
764
        $template->param( total_holds => $total_holds );
765
794
        if ( $patron && $multi_hold ) {
766
        if ( $patron && $multi_hold ) {
795
767
796
            # Add the valid pickup locations
768
            # Add the valid pickup locations
797
- 

Return to bug 23269