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

(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/reports/guided_reports_start.tt (-12 / +9 lines)
Lines 1071-1087 Link Here
1071
                                    >
1071
                                    >
1072
                                </form>
1072
                                </form>
1073
1073
1074
                                <form method="get" action="/cgi-bin/koha/tools/batch_modify_holds.pl" id="batch_modify_holds">
1074
                                <form method="post" action="/cgi-bin/koha/tools/batch_modify_holds.pl" id="batch_modify_holds" target="_blank">
1075
                                    <input type="hidden" name="op" value="list" />
1075
                                    [% INCLUDE 'csrf-token.inc' %]
1076
                                    [% FOREACH result IN results %]
1076
                                    <input type="hidden" name="op" value="cud-form" />
1077
                                        [% FOREACH cells IN result.cells %]
1077
                                    <textarea style="display:none" name="reserve_ids_list" id="reserve_ids_list">
1078
                                            [% place = loop.index %]
1078
                                    [%# Preserve the whitespace of the following textarea in order to format the values correctly %]
1079
                                            [% IF header_row.$place.cell == 'reserve_id' || header_types.item(header_row.$place.cell) == 'reserve_id' %]
1079
                                        [%- reserve_ids = PROCESS batch_list results=results batch_type='reserve_id' | trim | html %][% IF reserve_ids %][% SET batch_reserve_ids = 1 %][% reserve_ids | html %][% END -%]
1080
                                                [% SET batch_reserve_ids = 1 %]
1080
                                    </textarea
1081
                                                <input type="hidden" name="reserve_ids" value="[% cells.cell | html %]" />
1081
                                    >
1082
                                            [% END %]
1083
                                        [% END %]
1084
                                    [% END %]
1085
                                </form>
1082
                                </form>
1086
1083
1087
                                [% BLOCK batch_list %]
1084
                                [% BLOCK batch_list %]
Lines 1227-1233 Link Here
1227
                                                                    data-toggle="tooltip"
1224
                                                                    data-toggle="tooltip"
1228
                                                                    data-placement="right"
1225
                                                                    data-placement="right"
1229
                                                                    title="Send visible results to batch hold modification"
1226
                                                                    title="Send visible results to batch hold modification"
1230
                                                                    class="batch_op send_to_hold_mod"
1227
                                                                    class="batch_op send_to_hold_mod dropdown-item"
1231
                                                                    >Batch hold modification</a
1228
                                                                    >Batch hold modification</a
1232
                                                                >
1229
                                                                >
1233
                                                            </li>
1230
                                                            </li>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/batch_modify_holds.tt (-371 / +409 lines)
Lines 42-48 Link Here
42
        <div class="col-sm-10 col-sm-push-2 order-sm-1">
42
        <div class="col-sm-10 col-sm-push-2 order-sm-1">
43
            <main>
43
            <main>
44
                <h1>Batch modify holds</h1>
44
                <h1>Batch modify holds</h1>
45
                [% IF view == "form" %]
45
                [% IF view == "cud-form" %]
46
                    <div id="modify_holds_search">
46
                    <div id="modify_holds_search">
47
                        <form method="get" action="/cgi-bin/koha/tools/batch_modify_holds.pl" id="modify_holds_form">
47
                        <form method="get" action="/cgi-bin/koha/tools/batch_modify_holds.pl" id="modify_holds_form">
48
                            <fieldset class="rows">
48
                            <fieldset class="rows">
Lines 50-60 Link Here
50
                                <ol>
50
                                <ol>
51
                                    <li>
51
                                    <li>
52
                                        <label for="expirationdate_from">Expiration date from:</label>
52
                                        <label for="expirationdate_from">Expiration date from:</label>
53
                                        <input type="text" size="10" id="expirationdate_from" name="expirationdate_from" class="flatpickr" data-date_to="expirationdate_to" />
53
                                        <input type="text" size="10" id="expirationdate_from" name="expirationdate_from" class="flatpickr" />
54
                                    </li>
54
                                    </li>
55
                                    <li>
55
                                    <li>
56
                                        <label for="expirationdate_to">Expiration date to:</label>
56
                                        <label for="expirationdate_to">Expiration date to:</label>
57
                                        <input type="text" size="10" id="expirationdate_to" name="expirationdate_to" class="flatpickr"/>
57
                                        <input type="text" size="10" id="expirationdate_to" name="expirationdate_to" class="flatpickr" />
58
                                    </li>
58
                                    </li>
59
                                    <li>
59
                                    <li>
60
                                        <label for="branchcodes">Libraries:</label>
60
                                        <label for="branchcodes">Libraries:</label>
Lines 85-117 Link Here
85
                                    </li>
85
                                    </li>
86
                                    <li>
86
                                    <li>
87
                                        <label for="suspend_until_to">Suspended until to:</label>
87
                                        <label for="suspend_until_to">Suspended until to:</label>
88
                                        <input type="text" size="10" id="suspend_until_to" name="suspend_until_to" class="flatpickr"/>
88
                                        <input type="text" size="10" id="suspend_until_to" name="suspend_until_to" class="flatpickr" />
89
                                    </li>
89
                                    </li>
90
                                    <li>
90
                                    <li>
91
                                        <label for="holdnotes">Hold note:</label>
91
                                        <label for="holdnotes">Hold note:</label>
92
                                        <input type="text" id="holdnotes" name="holdnotes"/>
92
                                        <input type="text" id="holdnotes" name="holdnotes" />
93
                                    </li>
93
                                    </li>
94
                                </ol>
94
                                </ol>
95
                            </fieldset>
95
                            </fieldset>
96
                            <fieldset class="action">
96
                            <fieldset class="action">
97
                                <input type="submit" class="btn btn-primary" value="Search"/>
97
                                <input type="submit" class="btn btn-primary" value="Search" />
98
                            </fieldset>
98
                            </fieldset>
99
                        </form> <!-- /#modify_holds_form -->
99
                        </form>
100
                    </div> <!-- /#modify_holds_search -->
100
                        <!-- /#modify_holds_form -->
101
                    </div>
102
                    <!-- /#modify_holds_search -->
101
                [% ELSIF view == "report" %]
103
                [% ELSIF view == "report" %]
102
                    <div id="modified_holds_results-wrapper">
104
                    <div id="modified_holds_results-wrapper">
103
                        <div id="modified_holds_results" class="page-section">
105
                        <div id="modified_holds_results" class="page-section">
104
                            <table id="modified_holds"></table>
106
                            <table id="modified_holds"></table>
105
                        </div> <!-- /#modified_holds_results -->
107
                        </div>
108
                        <!-- /#modified_holds_results -->
106
                        <fieldset class="action">
109
                        <fieldset class="action">
107
                            <a href="/cgi-bin/koha/tools/batch_modify_holds.pl">Return to batch hold modification</a>
110
                            <a href="/cgi-bin/koha/tools/batch_modify_holds.pl">Return to batch hold modification</a>
108
                        </fieldset >
111
                        </fieldset>
109
                    </div> <!-- /#modified_holds_results-wrapper -->
112
                    </div>
113
                    <!-- /#modified_holds_results-wrapper -->
110
                [% END %]
114
                [% END %]
111
                <div id="modify_holds_results-wrapper" style="display:none;">
115
                <div id="modify_holds_results-wrapper" style="display:none;">
112
                    <div id="toolbar" class="btn-toolbar">
116
                    <div id="toolbar" class="btn-toolbar">
113
                        <a href="#" id="edit_search" class="btn btn-default"><i class="fa-solid fa-pencil" aria-hidden="true"></i> Edit search</a>
117
                        <a href="#" id="edit_search" class="btn btn-default"><i class="fa-solid fa-pencil" aria-hidden="true"></i> Edit search</a>
114
                    </div> <!-- /#toolbar -->
118
                    </div>
119
                    <!-- /#toolbar -->
115
                    <form action="/cgi-bin/koha/tools/batch_modify_holds.pl" method="post" id="process_mods">
120
                    <form action="/cgi-bin/koha/tools/batch_modify_holds.pl" method="post" id="process_mods">
116
                        [% INCLUDE 'csrf-token.inc' %]
121
                        [% INCLUDE 'csrf-token.inc' %]
117
                        <div id="modify_holds_results" class="page-section">
122
                        <div id="modify_holds_results" class="page-section">
Lines 122-131 Link Here
122
                                    <span></span>
127
                                    <span></span>
123
                                    <a href="#" id="clear-row-selection"><i class="fa fa-times"></i> Clear</a>
128
                                    <a href="#" id="clear-row-selection"><i class="fa fa-times"></i> Clear</a>
124
                                </div>
129
                                </div>
125
                            </div> <!-- /#searchheader -->
130
                            </div>
131
                            <!-- /#searchheader -->
126
                            <h3>Holds found for: <span class="searchpattern"></span></h3>
132
                            <h3>Holds found for: <span class="searchpattern"></span></h3>
127
                            <table id="holds_to_modify"></table>
133
                            <table id="holds_to_modify"></table>
128
                        </div> <!-- /#modify_holds_results -->
134
                        </div>
135
                        <!-- /#modify_holds_results -->
129
                        <div id="modify_holds_form_options" class="page-section">
136
                        <div id="modify_holds_form_options" class="page-section">
130
                            <h2>Modify holds</h2>
137
                            <h2>Modify holds</h2>
131
                            <table id="modify_holds_options">
138
                            <table id="modify_holds_options">
Lines 161-368 Link Here
161
                                            <input type="text" id="new_suspend_date" name="new_suspend_date" class="flatpickr" data-flatpickr-futuredate="true" />
168
                                            <input type="text" id="new_suspend_date" name="new_suspend_date" class="flatpickr" data-flatpickr-futuredate="true" />
162
                                        </td>
169
                                        </td>
163
                                        <td>
170
                                        <td>
164
                                           <input type="text" id="new_hold_note" name="new_hold_note"/>
171
                                            <input type="text" id="new_hold_note" name="new_hold_note" />
165
                                        </td>
172
                                        </td>
166
                                        <td>
173
                                        <td>
167
                                           <input class="selection" type="checkbox" id="clear_hold_notes" name="clear_hold_notes" value="1"/>
174
                                            <input class="selection" type="checkbox" id="clear_hold_notes" name="clear_hold_notes" value="1" />
168
                                        </td>
175
                                        </td>
169
                                    </tr>
176
                                    </tr>
170
                                </tbody>
177
                                </tbody>
171
                            </table> <!-- /#modify_holds_options -->
178
                            </table>
172
                        </div> <!-- /#modify_holds_options -->
179
                            <!-- /#modify_holds_options -->
180
                        </div>
181
                        <!-- /#modify_holds_options -->
173
                        <fieldset class="action">
182
                        <fieldset class="action">
174
                            <input type="hidden" name="op" value="cud-modify" />
183
                            <input type="hidden" name="op" value="cud-modify" />
175
                            <input type="submit" class="btn btn-primary" value="Modify holds" />
184
                            <input type="submit" class="btn btn-primary" value="Modify holds" />
176
                            <a class="cancel" href="/cgi-bin/koha/tools/batch_modify_holds.pl">Cancel</a>
185
                            <a class="cancel" href="/cgi-bin/koha/tools/batch_modify_holds.pl">Cancel</a>
177
                        </fieldset>
186
                        </fieldset>
178
                    </form> <!-- /#process_mods -->
187
                    </form>
179
                </div> <!-- /#modify_holds_results-wrapper -->
188
                    <!-- /#process_mods -->
189
                </div>
190
                <!-- /#modify_holds_results-wrapper -->
180
            </main>
191
            </main>
181
        </div> <!-- /.col-sm-10 col-sm-push-2 -->
192
        </div>
193
        <!-- /.col-sm-10 col-sm-push-2 -->
182
        <div class="col-sm-2 col-sm-pull-10">
194
        <div class="col-sm-2 col-sm-pull-10">
183
            <aside>
195
            <aside> [% INCLUDE 'tools-menu.inc' %] </aside>
184
                [% INCLUDE 'tools-menu.inc' %]
196
        </div>
185
            </aside>
197
        <!-- /.col-sm-2 col-sm-pull-10 -->
186
        </div> <!-- /.col-sm-2 col-sm-pull-10 -->
187
    </div>
198
    </div>
188
[% MACRO jsinclude BLOCK %]
199
    [% MACRO jsinclude BLOCK %]
189
    [% Asset.js("js/tools-menu.js") | $raw %]
200
        [% Asset.js("js/tools-menu.js") | $raw %]
190
    [% INCLUDE 'calendar.inc' %]
201
        [% INCLUDE 'calendar.inc' %]
191
    [% INCLUDE 'datatables.inc' %]
202
        [% INCLUDE 'datatables.inc' %]
192
    [% INCLUDE 'select2.inc' %]
203
        [% INCLUDE 'select2.inc' %]
193
    [% INCLUDE 'js-patron-format.inc' %]
204
        [% INCLUDE 'js-patron-format.inc' %]
194
    [% Asset.js("lib/jquery/plugins/humanmsg.js") | $raw %]
205
        [% Asset.js("lib/jquery/plugins/humanmsg.js") | $raw %]
195
    <script>
206
        <script>
196
        let hide_patron_name = [% IF Koha.Preference('HidePatronName') %]true[% ELSE %]false[% END %];
207
            let hide_patron_name = [% IF Koha.Preference('HidePatronName') %]true[% ELSE %]false[% END %];
197
        let hold_ids = [% IF updated_holds %] [% updated_holds | $raw %] [% ELSE %] [] [% END %];
208
            let hold_ids = [% IF updated_holds %] [% updated_holds | $raw %] [% ELSE %] [] [% END %];
198
209
            let hold_ids_from_sql = [% IF reserve_ids_list  %] [% reserve_ids_list  | $raw %] [% ELSE %] [] [% END %];
199
        $(document).ready(function() {
210
200
211
            $(document).ready(function() {
201
            // Apply select2 to all select fields having a "multiple" attribute
212
202
            let selectFields = document.querySelectorAll('select[multiple]');
213
                // Apply select2 to all select fields having a "multiple" attribute
203
            selectFields.forEach((selectField) => {
214
                let selectFields = document.querySelectorAll('select[multiple]');
204
                selectField.style.minWidth = '200px';
215
                selectFields.forEach((selectField) => {
205
                $(selectField).select2();
216
                    selectField.style.minWidth = '200px';
206
            });
217
                    $(selectField).select2();
218
                });
207
219
208
            //Empty local storage from previous selections
220
                //Empty local storage from previous selections
209
            localStorage.removeItem("holds_modify_selections");
221
                localStorage.removeItem("holds_modify_selections");
210
222
211
            $("#holds_to_modify").on("change", "input[type='checkbox']", function(){
223
                $("#holds_to_modify").on("change", "input[type='checkbox']", function(){
212
                var holds_modify_selections = JSON.parse(localStorage.getItem("holds_modify_selections")) || [];
224
                    var holds_modify_selections = JSON.parse(localStorage.getItem("holds_modify_selections")) || [];
213
                var hold_id = $(this).val();
225
                    var hold_id = $(this).val();
214
                if ($(this).prop("checked")) {
226
                    if ($(this).prop("checked")) {
215
                    holds_modify_selections.push($(this).val());
227
216
                    localStorage.setItem("holds_modify_selections", JSON.stringify(holds_modify_selections));
228
                        hold_data = {
217
                    showHoldSelections(holds_modify_selections.length);
229
                            hold_id: hold_id,
218
                } else {
230
                            found_status: $(this).closest('tr').find('.found_status').children('span').data('found-status'),
219
                    var filtered = holds_modify_selections.filter(function( value ){
231
                            suspended: $(this).closest('tr').find('.suspended').children('span').data('suspended'),
220
                        return value !== hold_id;
232
                        }
221
                    });
233
222
                    if( filtered.length > 0 ){
234
                        holds_modify_selections.push(hold_data);
223
                        localStorage.setItem("holds_modify_selections", JSON.stringify( filtered ));
235
                        localStorage.setItem("holds_modify_selections", JSON.stringify(holds_modify_selections));
224
                        holds_modify_selections = filtered;
236
                        showHoldSelections(holds_modify_selections.length);
225
                        showHoldSelections( filtered.length );
226
                    } else {
237
                    } else {
227
                        holds_modify_selections = [];
238
                        var filtered = holds_modify_selections.filter(function( hold_obj ){
228
                        localStorage.removeItem("holds_modify_selections");
239
                            return hold_obj.hold_id !== hold_id;
229
                        showHoldSelections( 0 );
240
                        });
241
                        if( filtered.length > 0 ){
242
                            localStorage.setItem("holds_modify_selections", JSON.stringify( filtered ));
243
                            holds_modify_selections = filtered;
244
                            showHoldSelections( filtered.length );
245
                        } else {
246
                            holds_modify_selections = [];
247
                            localStorage.removeItem("holds_modify_selections");
248
                            showHoldSelections( 0 );
249
                        }
230
                    }
250
                    }
231
                }
232
            });
233
234
            $("#select_all").on("click", function(e){
235
                e.preventDefault();
236
                $("#holds_to_modify input[type='checkbox']").each(function(){
237
                    $(this).prop("checked", true).change();
238
                });
251
                });
239
            });
240
252
241
            $("#clear_all").on("click", function(e){
253
                $("#select_all").on("click", function(e){
242
                e.preventDefault();
254
                    e.preventDefault();
243
                $("#holds_to_modify input[type='checkbox']").each(function(){
255
                    $("#holds_to_modify input[type='checkbox']").each(function(){
244
                    $(this).prop("checked", false).change();
256
                        $(this).prop("checked", true).change();
257
                    });
245
                });
258
                });
246
            });
247
259
248
            $("#clear-row-selection").on("click", function (e) {
260
                $("#clear_all").on("click", function(e){
249
                e.preventDefault();
261
                    e.preventDefault();
250
                $("input[type='checkbox']").prop("checked", false).change();
251
                localStorage.removeItem("holds_modify_selections");
252
                $("#table_search_selections").hide();
253
            });
254
255
            $('#modify_holds_form').submit(function() {
256
                var modify_holds_form = $(this);
257
                search_holds(modify_holds_form);
258
                $("#modify_holds_search").hide();
259
                $('#edit_search').show();
260
                return false;
261
            });
262
263
            $("#edit_search").on("click", function(e){
264
                e.preventDefault();
265
                $('#modify_holds_search').show();
266
                $('#edit_search').hide();
267
            });
268
269
            function prepSelections(){
270
                let holds_modify_selections = JSON.parse( localStorage.getItem("holds_modify_selections") ) || [];
271
                if( holds_modify_selections.length > 0 ){
272
                    showHoldSelections( holds_modify_selections.length );
273
                    $("#holds_to_modify input[type='checkbox']").each(function(){
262
                    $("#holds_to_modify input[type='checkbox']").each(function(){
274
                        var hold_id = $(this).val();
263
                        $(this).prop("checked", false).change();
275
                        if( holds_modify_selections.indexOf( hold_id ) >= 0 ){
276
                            $(this).prop("checked", true );
277
                        }
278
                    });
264
                    });
279
                }
265
                });
280
            }
281
266
282
            function showHoldSelections( number ){
267
                $("#clear-row-selection").on("click", function (e) {
283
                if (number === 0) {
268
                    e.preventDefault();
269
                    $("input[type='checkbox']").prop("checked", false).change();
270
                    localStorage.removeItem("holds_modify_selections");
284
                    $("#table_search_selections").hide();
271
                    $("#table_search_selections").hide();
285
                } else {
272
                });
286
                    $("#table_search_selections")
273
287
                        .show()
274
                $('#modify_holds_form').submit(function() {
288
                        .find("span")
275
                    var modify_holds_form = $(this);
289
                        .text(__("Holds selected: %s").format(number));
276
                    search_holds(modify_holds_form);
277
                    $("#modify_holds_search").hide();
278
                    $('#edit_search').show();
279
                    return false;
280
                });
281
282
                if(hold_ids_from_sql.length > 0){
283
                    $('#modify_holds_form').trigger('submit');
290
                }
284
                }
291
            }
292
285
293
            function search_holds(modify_holds_form){
286
                $("#edit_search").on("click", function(e){
294
                var table_settings = [% TablesSettings.GetTableSettings( 'circ', 'holds', 'holds_to_modify', 'json' ) | $raw %];
287
                    e.preventDefault();
295
                var searchpattern = "";
288
                    $('#modify_holds_search').show();
296
                var filters = {
289
                    $('#edit_search').hide();
297
                    "me.expirationdate": function(){
290
                });
298
                        var expirationdate_from = modify_holds_form.find("#expirationdate_from").val();
299
                        var expirationdate_to   = modify_holds_form.find("#expirationdate_to").val();
300
291
301
                        searchpattern += expirationdate_from && expirationdate_to ? _("expiration date between ")+ expirationdate_from + " and " + expirationdate_to + " ": "";
292
                function showHoldSelections( number ){
293
                    if (number === 0) {
294
                        $("#table_search_selections").hide();
295
                    } else {
296
                        $("#table_search_selections")
297
                            .show()
298
                            .find("span")
299
                            .text(__("Holds selected: %s").format(number));
300
                    }
301
                }
302
302
303
                        return expirationdate_from && expirationdate_to ? {"-between": [expirationdate_from, expirationdate_to]} : "";
303
                function search_holds(modify_holds_form){
304
                    },
304
                    var table_settings = [% TablesSettings.GetTableSettings( 'circ', 'holds', 'holds_to_modify', 'json' ) | $raw %];
305
                    "me.branchcode": function(){
305
                    var searchpattern = "";
306
                        var branchcodes = modify_holds_form.find("#branchcodes").val();
306
                    var filters = {
307
                        if( branchcodes.length > 0 ){
307
                        "me.expirationdate": function(){
308
                            searchpattern += _("from libraries ");
308
                            var expirationdate_from = modify_holds_form.find("#expirationdate_from").val();
309
                            var selected_libraries = modify_holds_form.find("#branchcodes option:selected");
309
                            var expirationdate_to   = modify_holds_form.find("#expirationdate_to").val();
310
                            $.each(selected_libraries, function(key, value) {
310
311
                                searchpattern += value.text + " ";
311
                            if (expirationdate_from && expirationdate_to){
312
                            });
312
                                searchpattern += _("expiration date between ") + expirationdate_from + " and " + expirationdate_to + " ";
313
                            return {"-in": branchcodes };
313
                                return {"-between": [expirationdate_from, expirationdate_to]};
314
                        }
314
                            }
315
                    },
315
                            else if (expirationdate_from && !expirationdate_to){
316
                    "me.status": function(){
316
                                searchpattern += _("expiration date from ") + expirationdate_from + " ";
317
                        var found_status = modify_holds_form.find("#found_status").val();
317
                                return {">=": expirationdate_from };
318
                        if( found_status.length > 0 ){
318
                            } else if (!expirationdate_from && expirationdate_to){
319
                            var filters = [{"-in": found_status}];
319
                                searchpattern += _("expiration date to ") + expirationdate_to + " ";
320
                            if(jQuery.inArray("NULL", found_status) !== -1){
320
                                return {"<=": expirationdate_to };
321
                                filters.push({"=": null});
321
                            }
322
                        },
323
                        "me.branchcode": function(){
324
                            var branchcodes = modify_holds_form.find("#branchcodes").val();
325
                            if( branchcodes.length > 0 ){
326
                                searchpattern += _("from libraries ");
327
                                var selected_libraries = modify_holds_form.find("#branchcodes option:selected");
328
                                $.each(selected_libraries, function(key, value) {
329
                                    searchpattern += value.text + " ";
330
                                });
331
                                return {"-in": branchcodes };
322
                            }
332
                            }
323
                            searchpattern += _("found status in ");
333
                        },
324
                            $.each(found_status, function(key, value) {
334
                        "me.status": function(){
325
                                let status = _("No status ");
335
                            var found_status = modify_holds_form.find("#found_status").val();
326
                                if ( value == "T" ) {
336
                            if( found_status.length > 0 ){
327
                                    status = _("In transit ");
337
                                var filters = [{"-in": found_status}];
328
                                } else if( value == "P" ) {
338
                                if(jQuery.inArray("NULL", found_status) !== -1){
329
                                    status = _("In processing ");
339
                                    filters.push({"=": null});
330
                                } else if( value == "W" ) {
331
                                    status = _("Waiting ");
332
                                }
340
                                }
333
                                searchpattern += status;
341
                                searchpattern += _("found status in ");
334
                            });
342
                                $.each(found_status, function(key, value) {
335
                            return filters;
343
                                    let status = _("No status ");
344
                                    if ( value == "T" ) {
345
                                        status = _("In transit ");
346
                                    } else if( value == "P" ) {
347
                                        status = _("In processing ");
348
                                    } else if( value == "W" ) {
349
                                        status = _("Waiting ");
350
                                    }
351
                                    searchpattern += status;
352
                                });
353
                                return filters;
354
                            }
355
                        },
356
                        "me.suspended": function(){
357
                            var suspend_status = modify_holds_form.find("#suspend_status").val();
358
359
                            if(suspend_status != "none"){
360
                                var suspended_text = suspend_status == 0 ? _("Not suspended") : _("Suspended");
361
                                searchpattern += _("with suspend status ") + suspended_text;
362
363
                                return {"=": suspend_status};
364
                            }
365
                        },
366
                        "me.suspend_until": function(){
367
                            var suspend_until_from  = modify_holds_form.find("#suspend_until_from").val();
368
                            var suspend_until_to    = modify_holds_form.find("#suspend_until_to").val();
369
370
                            searchpattern += suspend_until_from && suspend_until_to ? _("suspend date between ")+ suspend_until_from +" and "+suspend_until_to : "";
371
372
                            return suspend_until_from && suspend_until_to ? {"-between": [suspend_until_from, suspend_until_to]} : "";
373
                        },
374
                        "me.notes": function(){
375
                            var holdnotes = modify_holds_form.find("#holdnotes").val();
376
377
                            searchpattern += holdnotes ? _("hold notes like ") + holdnotes : "";
378
379
                            return holdnotes ? {"-like": "%"+holdnotes+"%"} : "";
380
                        },
381
                        "me.hold_id": function(){
382
                            return hold_ids_from_sql.length > 0 ? { "-in": hold_ids_from_sql } : "";
336
                        }
383
                        }
337
                    },
384
                    }
338
                    "me.suspended": function(){
339
                        var suspend_status = modify_holds_form.find("#suspend_status").val();
340
385
341
                        if(suspend_status != "none"){
386
                    var holds_modify_table = $("#holds_to_modify").kohaTable({
342
                            var suspended_text = suspend_status == 0 ? _("Not suspended") : _("Suspended");
387
                        "ajax": {
343
                            searchpattern += _("with suspend status ") + suspended_text;
388
                            "url": "/api/v1/holds"
389
                        },
390
                        "embed": [
391
                            "biblio",
392
                            "item",
393
                            "pickup_library",
394
                            "patron"
395
                        ],
396
                        "destroy": true,
397
                        "autoWidth": false,
398
                        "processing": true,
399
                        "columns": [
400
                            {
401
                                "data": "hold_id",
402
                                "name": "checkbox",
403
                                "orderable": false,
404
                                "render": function(data, type, row, meta) {
405
                                    return '<input class="selection" type="checkbox" value="'+ encodeURIComponent(data) +'"/>'
406
                                }
407
                            },
408
                            {
409
                                "data": "expiration_date",
410
                                "name": "expiration_date",
411
                                "type": "date",
412
                                "title": _("Expiration date"),
413
                                "orderable": true,
414
                                "render": function( data, type, row, meta ) {
415
                                    return $date(data);
416
                                }
417
                            },
418
                            {
419
                                "data": "biblio.title",
420
                                "name": "title",
421
                                "title": _("Title"),
422
                                "orderable": true,
423
                                "render": function( data, type, row, meta ) {
424
                                    return '<a href="/cgi-bin/koha/catalogue/detail.pl?' +
425
                                    'biblionumber=' + encodeURIComponent( row.biblio_id ) + '">' + escape_str( data ) + '</a>';
426
                                }
427
                            },
428
                            {
429
                                "data": "item.external_id",
430
                                "name": "barcode",
431
                                "title": _("Barcode"),
432
                                "defaultContent": _(""),
433
                                "orderable": true,
434
                                "render": function( data, type, row, meta ) {
435
                                    if( row.item ){
436
                                        let item_id = encodeURIComponent( row.item_id );
437
                                        let biblio_id = encodeURIComponent( row.biblio_id );
438
                                        return '<a href="/cgi-bin/koha/catalogue/moredetail.pl?' +
439
                                        'itemnumber='+ item_id +'&biblionumber='+ biblio_id +'&' +
440
                                        'bi='+ biblio_id +'#item'+ item_id +'">' + escape_str( data ) + '</a>'
441
                                    }
442
                                }
443
                            },
444
                            {
445
                                "data": "patron_id",
446
                                "name": "patron",
447
                                "title": _("Patron"),
448
                                "orderable": true,
449
                                "render": function( data, type, row, meta ) {
450
                                    let patron_to_html = $patron_to_html(row.patron, { url: true, display_cardnumber: true, hide_patron_name });
451
                                    return patron_to_html;
452
                                }
453
                            },
454
                            {
455
                                "data": "status",
456
                                "name": "status",
457
                                "title": _("Status"),
458
                                "className": "found_status",
459
                                "orderable": true,
460
                                "render": function( data, type, row, meta ) {
461
                                    let status = _("No status");
462
                                    if ( data == "T" ) {
463
                                        status = _("In transit");
464
                                    } else if( data == "P" ) {
465
                                        status = _("In processing");
466
                                    } else if( data == "W" ) {
467
                                        status = _("Waiting");
468
                                    }
469
                                    return "<span data-found-status='" + escape_str( data ) + "'>" + status + "</span>";
470
                                }
471
                            },
472
                            {
473
                                "data": "pickup_library_id",
474
                                "name": "pickup_library",
475
                                "title": _("Hold pickup library"),
476
                                "orderable": true,
477
                                "render": function( data, type, row, meta ) {
478
                                    return escape_str( row.pickup_library.name );
479
                                }
480
                            },
481
                            {
482
                                "data": "suspended",
483
                                "name": "suspended",
484
                                "className": "suspended",
485
                                "title": _("Suspended"),
486
                                "orderable": true,
487
                                "render": function( data, type, row, meta ) {
488
                                    var suspended_string = data == 0 ? _("No") : _("Yes");
489
                                    return "<span data-suspended='" + data + "'>" + suspended_string + "</span>";
490
                                }
491
                            },
492
                            {
493
                                "data": "suspended_until",
494
                                "name": "suspended_until",
495
                                "title": _("Suspended until"),
496
                                "orderable": true,
497
                                "render": function( data, type, row, meta ) {
498
                                    return $date( data );
499
                                }
500
                            },
501
                            {
502
                                "data": "notes",
503
                                "name": "notes",
504
                                "title": _("Notes"),
505
                                "orderable": true,
506
                                "render": function( data, type, row, meta ) {
507
                                    return escape_str( data );
508
                                }
509
                            }
510
                        ],
511
                    }, table_settings, 0, filters);
344
512
345
                            return {"=": suspend_status};
513
                    $(".searchpattern").text(searchpattern);
514
515
                    $("#modify_holds_results-wrapper").show();
516
                }
517
518
                $("#process_mods").on('submit', function(e) {
519
520
                    var hold_ids = JSON.parse( localStorage.getItem("holds_modify_selections") ) || [];
521
522
                    $("#process_mods input[name='hold_id']").remove();
523
524
                    hold_ids.forEach(function(hold) {
525
                        $('<input>').attr({
526
                            type: 'hidden',
527
                            name: 'hold_id',
528
                            value: hold.hold_id
529
                        }).appendTo('#process_mods');
530
                    });
531
532
                    var errors = [];
533
534
                    var new_expiration_date = $("#new_expiration_date").val();
535
                    var new_pickup_loc      = $("#new_pickup_loc").val();
536
                    var new_suspend_status  = $("#new_suspend_status").val();
537
                    var new_suspend_date    = $("#new_suspend_date").val();
538
                    var new_hold_note       = $("#new_hold_note").val();
539
                    var clear_hold_notes    = $("#clear_hold_notes").val();
540
541
                    if ( hold_ids.length == 0 ) {
542
                        e.preventDefault();
543
                        errors.push(_("Please select at least one hold to process."));
544
                    }
545
546
                    if( new_pickup_loc || new_suspend_status || new_suspend_date ){
547
                        var found = false;
548
                        hold_ids.forEach(function(hold){
549
                            if( hold.found_status ){
550
                                e.preventDefault();
551
                                found = true;
552
                            }
553
                        });
554
                        if( ( new_suspend_status || new_suspend_date ) && found ){
555
                            errors.push(_("One or more holds have found status and can't be suspended."));
346
                        }
556
                        }
347
                    },
557
                        if( new_pickup_loc && found ){
348
                    "me.suspend_until": function(){
558
                            errors.push(_("One or more holds have found status and their pick up location can't be changed."));
349
                        var suspend_until_from  = modify_holds_form.find("#suspend_until_from").val();
559
                        }
350
                        var suspend_until_to    = modify_holds_form.find("#suspend_until_to").val();
560
                    }
351
561
352
                        searchpattern += suspend_until_from && suspend_until_to ? _("suspend date between ")+ suspend_until_from +"-"+suspend_until_to : "";
562
                    var suspended = false;
353
563
354
                        return suspend_until_from && suspend_until_to ? {"-between": [suspend_until_from, suspend_until_to]} : "";
564
                    hold_ids.forEach(function(hold){
355
                    },
565
                        if( hold.suspened ){
356
                    "me.notes": function(){
566
                            suspended = true;
357
                        var holdnotes = modify_holds_form.find("#holdnotes").val();
567
                        }
568
                    });
358
569
359
                        searchpattern += holdnotes ? _("hold notes like ") + holdnotes : "";
570
                    if( ( !new_suspend_status || new_suspend_status == "0" || !suspended ) && new_suspend_date ){
571
                        new_suspend_status = 1;
572
                    }
360
573
361
                        return holdnotes ? {"-like": "%"+holdnotes+"%"} : "";
574
                    if (errors.length > 0) {
575
                        e.preventDefault();
576
                        $("#errorList").html(errors.map(error => `<li>${error}</li>`).join(""));
577
                        $("#errorModal").modal('show');
578
                        return false;
579
                    }
580
                    return true;
581
                });
582
583
                //Modified holds table
584
                var table_settings = [% TablesSettings.GetTableSettings( 'circ', 'holds', 'modified_holds', 'json' ) | $raw %];
585
                var filters = {
586
                    "me.hold_id": function(){
587
                        return {"-in": hold_ids};
362
                    }
588
                    }
363
                }
589
                }
364
590
365
                var holds_modify_table = $("#holds_to_modify").kohaTable({
591
                var holds_modified_table = $("#modified_holds").kohaTable({
366
                    "ajax": {
592
                    "ajax": {
367
                        "url": "/api/v1/holds"
593
                        "url": "/api/v1/holds"
368
                    },
594
                    },
Lines 376-389 Link Here
376
                    "autoWidth": false,
602
                    "autoWidth": false,
377
                    "processing": true,
603
                    "processing": true,
378
                    "columns": [
604
                    "columns": [
379
                        {
380
                            "data": "hold_id",
381
                            "name": "checkbox",
382
                            "orderable": false,
383
                            "render": function(data, type, row, meta) {
384
                                return '<input class="selection" type="checkbox" name="hold_id" value="'+ encodeURIComponent(data) +'"/>'
385
                            }
386
                        },
387
                        {
605
                        {
388
                            "data": "expiration_date",
606
                            "data": "expiration_date",
389
                            "name": "expiration_date",
607
                            "name": "expiration_date",
Lines 445-451 Link Here
445
                                } else if( data == "W" ) {
663
                                } else if( data == "W" ) {
446
                                    status = _("Waiting");
664
                                    status = _("Waiting");
447
                                }
665
                                }
448
                                return "<span data-found-status='" + escape_str( data ) + "'>" + status + "</span>";
666
                                return status;
449
                            }
667
                            }
450
                        },
668
                        },
451
                        {
669
                        {
Lines 484-678 Link Here
484
                                return escape_str( data );
702
                                return escape_str( data );
485
                            }
703
                            }
486
                        }
704
                        }
487
                    ],
705
                    ]
488
                    "drawCallback": function( settings ) {
489
                        prepSelections();
490
                    },
491
                }, table_settings, 0, filters);
706
                }, table_settings, 0, filters);
492
707
493
                $(".searchpattern").text(searchpattern);
708
                var modified_message = '<div class="alert alert-info">'+hold_ids.length+' hold(s) have been modified!</div>';
494
709
                $("#modified_holds_results-wrapper").prepend(modified_message);
495
                $("#modify_holds_results-wrapper").show();
496
            }
497
498
            $("#process_mods").on('submit', function(e) {
499
500
                var hold_ids = [];
501
                var errors = [];
502
                var holds_checked = $("input[type=checkbox][name='hold_id']:checked");
503
504
                var new_expiration_date = $("#new_expiration_date").val();
505
                var new_pickup_loc      = $("#new_pickup_loc").val();
506
                var new_suspend_status  = $("#new_suspend_status").val();
507
                var new_suspend_date    = $("#new_suspend_date").val();
508
                var new_hold_note       = $("#new_hold_note").val();
509
                var clear_hold_notes    = $("#clear_hold_notes").val();
510
710
511
                if ( holds_checked.length == 0 ) {
512
                    e.preventDefault();
513
                    errors.push(_("Please select at least one hold to process."));
514
                }
515
516
                if( new_pickup_loc || new_suspend_status ){
517
                    var found = false;
518
                    holds_checked.each(function(){
519
                        if($(this).parents("tr").children(".found_status").children("span").data("found-status")){
520
                            e.preventDefault();
521
                            found = true;
522
                        }
523
                    });
524
                    if( new_suspend_status && found ){
525
                        errors.push(_("One or more holds have found status and can't be suspended."));
526
                    }
527
                    if( new_pickup_loc && found ){
528
                        errors.push(_("One or more holds have found status and their pick up location can't be changed."));
529
                    }
530
                }
531
                if( ( !new_suspend_status || new_suspend_status == "0") && new_suspend_date ){
532
                    e.preventDefault();
533
                    errors.push(_("You have to suspend holds if new suspend until date is set."));
534
                }
535
536
                if (errors.length > 0) {
537
                    e.preventDefault();
538
                    $("#errorList").html(errors.map(error => `<li>${error}</li>`).join(""));
539
                    $("#errorModal").modal('show');
540
                    return false;
541
                }
542
543
                return true;
544
            });
711
            });
712
        </script>
713
    [% END %]
545
714
546
            //Modified holds table
715
    [% INCLUDE 'intranet-bottom.inc' %]
547
            var table_settings = [% TablesSettings.GetTableSettings( 'circ', 'holds', 'modified_holds', 'json' ) | $raw %];
716
</div>
548
            var filters = {
549
                "me.hold_id": function(){
550
                    return {"-in": hold_ids};
551
                }
552
            }
553
554
            var holds_modified_table = $("#modified_holds").kohaTable({
555
                "ajax": {
556
                    "url": "/api/v1/holds"
557
                },
558
                "embed": [
559
                    "biblio",
560
                    "item",
561
                    "pickup_library",
562
                    "patron"
563
                ],
564
                "destroy": true,
565
                "autoWidth": false,
566
                "processing": true,
567
                "columns": [
568
                    {
569
                        "data": "expiration_date",
570
                        "name": "expiration_date",
571
                        "type": "date",
572
                        "title": _("Expiration date"),
573
                        "orderable": true,
574
                        "render": function( data, type, row, meta ) {
575
                            return $date(data);
576
                        }
577
                    },
578
                    {
579
                        "data": "biblio.title",
580
                        "name": "title",
581
                        "title": _("Title"),
582
                        "orderable": true,
583
                        "render": function( data, type, row, meta ) {
584
                            return '<a href="/cgi-bin/koha/catalogue/detail.pl?' +
585
                            'biblionumber=' + encodeURIComponent( row.biblio_id ) + '">' + escape_str( data ) + '</a>';
586
                        }
587
                    },
588
                    {
589
                        "data": "item.external_id",
590
                        "name": "barcode",
591
                        "title": _("Barcode"),
592
                        "defaultContent": _(""),
593
                        "orderable": true,
594
                        "render": function( data, type, row, meta ) {
595
                            if( row.item ){
596
                                let item_id = encodeURIComponent( row.item_id );
597
                                let biblio_id = encodeURIComponent( row.biblio_id );
598
                                return '<a href="/cgi-bin/koha/catalogue/moredetail.pl?' +
599
                                'itemnumber='+ item_id +'&biblionumber='+ biblio_id +'&' +
600
                                'bi='+ biblio_id +'#item'+ item_id +'">' + escape_str( data ) + '</a>'
601
                            }
602
                        }
603
                    },
604
                    {
605
                        "data": "patron_id",
606
                        "name": "patron",
607
                        "title": _("Patron"),
608
                        "orderable": true,
609
                        "render": function( data, type, row, meta ) {
610
                            let patron_to_html = $patron_to_html(row.patron, { url: true, display_cardnumber: true, hide_patron_name });
611
                            return patron_to_html;
612
                        }
613
                    },
614
                    {
615
                        "data": "status",
616
                        "name": "status",
617
                        "className": "found_status",
618
                        "title": _("Status"),
619
                        "orderable": true,
620
                        "render": function( data, type, row, meta ) {
621
                            let status = _("No status");
622
                            if ( data == "T" ) {
623
                                status = _("In transit");
624
                            } else if( data == "P" ) {
625
                                status = _("In processing");
626
                            } else if( data == "W" ) {
627
                                status = _("Waiting");
628
                            }
629
                            return status;
630
                        }
631
                    },
632
                    {
633
                        "data": "pickup_library_id",
634
                        "name": "pickup_library",
635
                        "title": _("Hold pickup library"),
636
                        "orderable": true,
637
                        "render": function( data, type, row, meta ) {
638
                            return escape_str( row.pickup_library.name );
639
                        }
640
                    },
641
                    {
642
                        "data": "suspended",
643
                        "name": "suspended",
644
                        "title": _("Suspended"),
645
                        "orderable": true,
646
                        "render": function( data, type, row, meta ) {
647
                            return data == 0 ? _("No") : _("Yes");
648
                        }
649
                    },
650
                    {
651
                        "data": "suspended_until",
652
                        "name": "suspended_until",
653
                        "title": _("Suspended until"),
654
                        "orderable": true,
655
                        "render": function( data, type, row, meta ) {
656
                            return $date( data );
657
                        }
658
                    },
659
                    {
660
                        "data": "notes",
661
                        "name": "notes",
662
                        "title": _("Notes"),
663
                        "orderable": true,
664
                        "render": function( data, type, row, meta ) {
665
                            return escape_str( data );
666
                        }
667
                    }
668
                ]
669
            }, table_settings, 0, filters);
670
671
            var modified_message = '<div class="alert alert-info">'+hold_ids.length+' hold(s) have been modified!</div>';
672
            $("#modified_holds_results-wrapper").prepend(modified_message);
673
674
        });
675
    </script>
676
[% END %]
677
678
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/tools/batch_modify_holds.pl (-13 / +18 lines)
Lines 30-36 use Koha::DateUtils qw( dt_from_string ); Link Here
30
use Koha::Holds;
30
use Koha::Holds;
31
31
32
my $input = CGI->new;
32
my $input = CGI->new;
33
my $op    = $input->param('op') // q|form|;
33
my $op    = $input->param('op') // q|cud-form|;
34
34
35
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
35
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
36
    {
36
    {
Lines 43-50 my ( $template, $loggedinuser, $cookie ) = get_template_and_user( Link Here
43
43
44
my @hold_ids;
44
my @hold_ids;
45
45
46
if ( $op eq 'form' ) {
46
if ( $op eq 'cud-form' ) {
47
    $template->param( view => 'form', );
47
    my $reserve_ids_list = $input->param('reserve_ids_list') || undef;
48
    if ($reserve_ids_list) {
49
        my @reserve_ids = split /\n/, $reserve_ids_list;
50
        $template->param( reserve_ids_list => to_json( \@reserve_ids ), );
51
    }
52
    $template->param( view => 'cud-form', );
48
} elsif ( $op eq 'cud-modify' ) {
53
} elsif ( $op eq 'cud-modify' ) {
49
    my $new_expiration_date = $input->param('new_expiration_date');
54
    my $new_expiration_date = $input->param('new_expiration_date');
50
    my $new_pickup_loc      = $input->param('new_pickup_loc');
55
    my $new_pickup_loc      = $input->param('new_pickup_loc');
Lines 68-85 if ( $op eq 'form' ) { Link Here
68
            $hold->branchcode($new_pickup_loc)->store;
73
            $hold->branchcode($new_pickup_loc)->store;
69
        }
74
        }
70
75
71
        if ( $new_suspend_status ne "" && !$hold->is_found ) {
76
        if ( $new_suspend_status && $new_suspend_status ne "" && !$hold->is_found ) {
72
            if ($new_suspend_status) {
77
            $hold->suspend(1)->store;
73
                $hold->suspend(1)->store;
78
            if ($new_suspend_date) {
74
                if ($new_suspend_date) {
79
                $hold->suspend_until($new_suspend_date)->store;
75
                    $hold->suspend_until($new_suspend_date)->store;
76
                } else {
77
                    $hold->suspend_until(undef)->store;
78
                }
79
            } else {
80
            } else {
80
                $hold->suspend(0)->store;
81
                $hold->suspend_until(undef)->store;
81
                $hold->suspend_until(undef)->store;
82
            }
82
            }
83
        } elsif ( !$new_suspend_status && $new_suspend_date ) {
84
            $hold->suspend(1)->store;
85
            $hold->suspend_until($new_suspend_date)->store;
86
        } else {
87
            $hold->suspend(0)->store;
88
            $hold->suspend_until(undef)->store;
83
        }
89
        }
84
90
85
        if ($new_hold_note) {
91
        if ($new_hold_note) {
86
- 

Return to bug 36135