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

(-)a/koha-tmpl/intranet-tmpl/prog/js/checkouts.js (-467 / +468 lines)
Lines 1-9 Link Here
1
/* global __ */
1
/* global __ */
2
2
3
$(document).ready(function() {
4
    var loadIssuesTableDelayTimeoutId;
5
3
6
    var barcodefield = $("#barcode");
4
function RefreshIssuesTable() {
5
    var table = $('#issues-table').DataTable();
6
    var renewchecked = $('input[name=renew]:checked').map(function(){
7
        return this.value;
8
    }).get();
9
    var checkinchecked = $('input[name=checkin]:checked').map(function(){
10
        return this.value;
11
    }).get();
12
    table.ajax.reload( function() {
13
        $('#RenewChecked, #CheckinChecked').prop('disabled' , true );
14
        if ( renewchecked.length ) {
15
            $('#RenewChecked').prop('disabled' , false );
16
            renewchecked.forEach( function(checked) {
17
                $('.renew[value="'+checked+'"]').prop('checked' , true );
18
            });
19
        }
20
        if ( checkinchecked.length ) {
21
            $('#CheckinChecked').prop('disabled' , false );
22
            checkinchecked.forEach( function(checked) {
23
                $('.checkin[value="'+checked+'"]').prop('checked' , true );
24
            });
25
        }
26
    var checkout_count = table.page.info().recordsTotal;
27
    $('.checkout_count').text(checkout_count);
28
    });
29
}
30
31
function LoadIssuesTable() {
32
    $('#issues-table-loading-message').hide();
33
    $('#issues-table').show();
34
    $('#issues-table-actions').show();
35
    var msg_loading = __('Loading... you may continue scanning.');
36
    issuesTable = KohaTable("issues-table", {
37
        "language":  {
38
            "emptyTable":  msg_loading,
39
            "processing": msg_loading,
40
        },
41
        "autoWidth":  false,
42
        "dom": '<"table_controls"B>rt',
43
        "columns":  [
44
            {
45
                "data": function( oObj ) {
46
                    return oObj.sort_order;
47
                }
48
            },
49
            {
50
                "data": function( oObj ) {
51
                    if ( oObj.issued_today ) {
52
                        return "<strong>" + __("Today's checkouts") + "</strong>";
53
                    } else {
54
                        return "<strong>" + __("Previous checkouts") + "</strong>";
55
                    }
56
                }
57
            },
58
            {
59
                "data": "date_due",
60
                "visible":  false,
61
            },
62
            {
63
                "orderData":  2, // Sort on hidden unformatted date due column
64
                "data": function( oObj ) {
65
                    let date_due_formatted = $datetime(oObj.date_due, { as_due_date: true, no_tz_adjust: true });
66
                    var due = oObj.date_due_overdue
67
                        ? "<span class='overdue'>" + date_due_formatted + "</span>"
68
                        : date_due_formatted;
69
70
                    due = "<span id='date_due_" + oObj.itemnumber + "' class='date_due'>" + due + "</span>";
71
72
                    if ( oObj.lost && oObj.claims_returned ) {
73
                        due += "<span class='lost claims_returned'>" + oObj.lost.escapeHtml() + "</span>";
74
                    } else if ( oObj.lost ) {
75
                        due += "<span class='lost'>" + oObj.lost.escapeHtml() + "</span>";
76
                    }
77
78
                    if ( oObj.damaged ) {
79
                        due += "<span class='dmg'>" + oObj.damaged.escapeHtml() + "</span>";
80
                    }
81
82
                    var patron_note = " <span class='patron_note_" + oObj.itemnumber + "'></span>";
83
                    due +="<br>" + patron_note;
84
85
                    return due;
86
                }
87
            },
88
            {
89
                "data": function ( oObj ) {
90
                    let title = "<span id='title_" + oObj.itemnumber + "' class='strong'><a href='/cgi-bin/koha/catalogue/detail.pl?biblionumber="
91
                          + oObj.biblionumber
92
                          + "'>"
93
                          + (oObj.title ? oObj.title.escapeHtml() : '' );
94
95
                    $.each(oObj.subtitle, function( index, value ) {
96
                              title += " " + value.escapeHtml();
97
                    });
98
99
                    title += " " + oObj.part_number + " " + oObj.part_name;
100
101
                    if ( oObj.enumchron ) {
102
                        title += " <span class='item_enumeration'>(" + oObj.enumchron.escapeHtml() + ")</span>";
103
                    }
104
105
                    title += "</a></span>";
106
107
                    if ( oObj.author ) {
108
                        title += " " + __("by _AUTHOR_").replace( "_AUTHOR_",  " " + oObj.author.escapeHtml() );
109
                    }
110
111
                    if ( oObj.itemnotes ) {
112
                        var span_class = "text-muted";
113
                        if ( flatpickr.formatDate( new Date(oObj.issuedate), "Y-m-d" ) == ymd ){
114
                            span_class = "circ-hlt";
115
                        }
116
                        title += "<span class='divider-dash'> - </span><span class='" + span_class + " item-note-public'>" + oObj.itemnotes.escapeHtml() + "</span>";
117
                    }
118
119
                    if ( oObj.itemnotes_nonpublic ) {
120
                        var span_class = "text-danger";
121
                        if ( flatpickr.formatDate( new Date(oObj.issuedate), "Y-m-d" ) == ymd ){
122
                            span_class = "circ-hlt";
123
                        }
124
                        title += "<span class='divider-dash'> - </span><span class='" + span_class + " item-note-nonpublic'>" + oObj.itemnotes_nonpublic.escapeHtml() + "</span>";
125
                    }
126
127
                    var onsite_checkout = '';
128
                    if ( oObj.onsite_checkout == 1 ) {
129
                        onsite_checkout += " <span class='onsite_checkout'>(" + __("On-site checkout") + ")</span>";
130
                    }
131
132
                    if ( oObj.recalled == 1 ) {
133
                         title += "<span class='divider-dash'> - </span><span class='circ-hlt item-recalled'>" +  __("This item has been recalled and the due date updated") + ".</span>";
134
                    }
135
136
                    title += " "
137
                          + "<a href='/cgi-bin/koha/catalogue/moredetail.pl?biblionumber="
138
                          + oObj.biblionumber
139
                          + "&itemnumber="
140
                          + oObj.itemnumber
141
                          + "#"
142
                          + oObj.itemnumber
143
                          + "'>"
144
                          + (oObj.barcode ? oObj.barcode.escapeHtml() : "")
145
                          + "</a>"
146
                          + onsite_checkout
147
148
                    return title;
149
                },
150
                "type":  "anti-the"
151
            },
152
            {
153
                "data": function ( oObj ) {
154
                    return oObj.recordtype_description.escapeHtml();
155
                }
156
            },
157
            {
158
                "data": function ( oObj ) {
159
                    return oObj.itemtype_description.escapeHtml();
160
                }
161
            },
162
            {
163
                "data": function ( oObj ) {
164
                    return ( oObj.collection ? oObj.collection.escapeHtml() : '' );
165
                }
166
            },
167
            {
168
                "data": function ( oObj ) {
169
                    return ( oObj.location ? oObj.location.escapeHtml() : '' );
170
                }
171
            },
172
            {
173
                "data": function ( oObj ) {
174
                    return (oObj.homebranch ? oObj.homebranch.escapeHtml() : '' );
175
                }
176
            },
177
            {
178
                "data": "issuedate",
179
                "visible":  false,
180
            },
181
            {
182
                "orderData":  10, // Sort on hidden unformatted issuedate column
183
                "data": function( oObj ) {
184
                    return $datetime(oObj.issuedate, { no_tz_adjust: true });
185
                }
186
            },
187
            {
188
                "data": function ( oObj ) {
189
                    return (oObj.branchname ? oObj.branchname.escapeHtml() : '' );
190
                }
191
            },
192
            {
193
                "data": function ( oObj ) {
194
                    return ( oObj.itemcallnumber ? oObj.itemcallnumber.escapeHtml() : '' );
195
                }
196
            },
197
            {
198
                "data": function ( oObj ) {
199
                    return ( oObj.copynumber ? oObj.copynumber.escapeHtml() : '' );
200
                }
201
            },
202
            {
203
                "data": function ( oObj ) {
204
                    if ( ! oObj.charge ) oObj.charge = 0;
205
                    return '<span style="text-align: right; display: block;">' + parseFloat(oObj.charge).format_price() + '<span>';
206
                },
207
                "className": "nowrap"
208
            },
209
            {
210
                "data": function ( oObj ) {
211
                    if ( ! oObj.fine ) oObj.fine = 0;
212
                    return '<span style="text-align: right; display: block;">' + parseFloat(oObj.fine).format_price()   + '<span>';
213
                },
214
                "className": "nowrap"
215
            },
216
            {
217
                "data": function ( oObj ) {
218
                    if ( ! oObj.price ) oObj.price = 0;
219
                    return '<span style="text-align: right; display: block;">' + parseFloat(oObj.price).format_price()  + '<span>';
220
                },
221
                "className": "nowrap"
222
            },
223
            {
224
                "orderable":  false,
225
                "visible":  AllowCirculate ? true : false,
226
                "data": function ( oObj ) {
227
                    var content = "";
228
                    var msg = "";
229
                    var span_style = "";
230
                    var span_class = "";
231
232
                    if ( oObj.can_renew ) {
233
                        // Do nothing
234
                    } else if ( oObj.can_renew_error == "recalled" ) {
235
                        msg += "<span>"
236
                                + "<a href='/cgi-bin/koha/recalls/request.pl?biblionumber=" + oObj.biblionumber + "'>" + __("Recalled") + "</a>"
237
                                + "</span>";
238
239
                        span_style = "display: none";
240
                        span_class = "renewals-allowed-recalled";
241
                    } else if ( oObj.can_renew_error == "on_reserve" ) {
242
                        msg += "<span>"
243
                                +"<a href='/cgi-bin/koha/reserve/request.pl?biblionumber=" + oObj.biblionumber + "'>" + __("On hold") + "</a>"
244
                                + "</span>";
245
246
                        span_style = "display: none";
247
                        span_class = "renewals-allowed-on_reserve";
248
                    } else if ( oObj.can_renew_error == "too_many" ) {
249
                        msg += "<span class='renewals-disabled'>"
250
                                + __("Not renewable")
251
                                + "</span>";
252
253
                        span_style = "display: none";
254
                        span_class = "renewals-allowed";
255
                    } else if ( oObj.can_renew_error == "too_unseen" ) {
256
                        msg += "<span>"
257
                                + __("Must be renewed at the library")
258
                                + "</span>";
259
                        span_class = "renewals-allowed";
260
                    } else if ( oObj.can_renew_error == "restriction" ) {
261
                        msg += "<span class='renewals-disabled'>"
262
                                + __("Not allowed: patron restricted")
263
                                + "</span>";
264
265
                        span_style = "display: none";
266
                        span_class = "renewals-allowed";
267
                    } else if ( oObj.can_renew_error == "overdue" ) {
268
                        msg += "<span class='renewals-disabled'>"
269
                                + __("Not allowed: overdue")
270
                                + "</span>";
271
272
                        span_style = "display: none";
273
                        span_class = "renewals-allowed";
274
                    } else if ( oObj.can_renew_error == "too_soon" ) {
275
                        msg += "<span class='renewals-disabled'>"
276
                                + __("No renewal before %s").format(oObj.can_renew_date)
277
                                + "</span>";
278
279
                        span_style = "display: none";
280
                        span_class = "renewals-allowed";
281
                    } else if ( oObj.can_renew_error == "auto_too_late" ) {
282
                        msg += "<span class='renewals-disabled'>"
283
                                + __("Can no longer be auto-renewed - number of checkout days exceeded")
284
                                + "</span>";
285
286
                        span_style = "display: none";
287
                        span_class = "renewals-allowed";
288
                    } else if ( oObj.can_renew_error == "auto_too_much_oweing" ) {
289
                        msg += "<span class='renewals-disabled'>"
290
                                + __("Automatic renewal failed, patron has unpaid fines")
291
                                + "</span>";
292
293
                        span_style = "display: none";
294
                        span_class = "renewals-allowed";
295
                    } else if ( oObj.can_renew_error == "auto_account_expired" ) {
296
                        msg += "<span class='renewals-disabled'>"
297
                                + __("Automatic renewal failed, account expired")
298
                                + "</span>";
299
300
                        span_style = "display: none";
301
                        span_class = "renewals-allowed";
302
                    } else if ( oObj.can_renew_error == "onsite_checkout" ) {
303
                        // Don't display something if it's an onsite checkout
304
                    } else if ( oObj.can_renew_error == "item_denied_renewal" ) {
305
                        content += "<span class='renewals-disabled'>"
306
                                + __("Renewal denied by syspref")
307
                                + "</span>";
308
309
                        span_style = "display: none";
310
                        span_class = "renewals-allowed";
311
                    } else {
312
                        msg += "<span class='renewals-disabled'>"
313
                                + oObj.can_renew_error
314
                                + "</span>";
315
316
                        span_style = "display: none";
317
                        span_class = "renewals-allowed";
318
                    }
319
320
                    var can_force_renew = ( oObj.onsite_checkout == 0 ) &&
321
                        ( oObj.can_renew_error != "on_reserve" || (oObj.can_renew_error == "on_reserve" && AllowRenewalOnHoldOverride))
322
                        ? true : false;
323
                    var can_renew = ( oObj.renewals_remaining > 0 && ( !oObj.can_renew_error || oObj.can_renew_error == "too_unseen" ));
324
                    content += "<span>";
325
                    if ( can_renew || can_force_renew ) {
326
                        content += "<span style='padding: 0 1em;'>" + oObj.renewals_count + "</span>";
327
                        content += "<span class='" + span_class + "' style='" + span_style + "'>"
328
                                +  "<input type='checkbox' ";
329
                        if ( oObj.date_due_overdue && can_renew ) {
330
                            content += "checked='checked' ";
331
                        }
332
                        if (oObj.can_renew_error == "on_reserve") {
333
                            content += "data-on-reserve ";
334
                        }
335
                        content += "class='renew' id='renew_" + oObj.itemnumber + "' name='renew' value='" + oObj.itemnumber +"'/>"
336
                                +  "</span>";
337
                    }
338
                    content += msg;
339
                    if ( can_renew || can_force_renew ) {
340
                        content += "<span class='renewals-info'>(";
341
                        content += __("%s of %s renewals remaining").format(oObj.renewals_remaining, oObj.renewals_allowed);
342
                        if (UnseenRenewals && oObj.unseen_allowed) {
343
                            content += __(" and %s of %s unseen renewals remaining").format(oObj.unseen_remaining, oObj.unseen_allowed);
344
                        }
345
                        content += ")</span>";
346
                    }
347
                    if(oObj.auto_renew){
348
                        content += "<span class='renewals-info'>(";
349
                        content += __("Scheduled for automatic renewal");
350
                        content += ")</span>";
351
                    }
352
353
                    return content;
354
                }
355
            },
356
            {
357
                "orderable":  false,
358
                "visible":  AllowCirculate ? true : false,
359
                "data": function ( oObj ) {
360
                    if ( oObj.can_renew_error == "recalled" ) {
361
                        return "<a href='/cgi-bin/koha/recalls/request.pl?biblionumber=" + oObj.biblionumber + "'>" + __("Recalled") + "</a>";
362
                    } else if ( oObj.can_renew_error == "on_reserve" ) {
363
                        return "<a href='/cgi-bin/koha/reserve/request.pl?biblionumber=" + oObj.biblionumber + "'>" + __("On hold") + "</a>";
364
                    } else if ( oObj.materials ) {
365
                        return "<input type='checkbox' class='confirm' id='confirm_" + oObj.itemnumber + "' name='confirm' value='" + oObj.itemnumber + "' data-materials='" + oObj.materials.escapeHtml() + "'></input>";
366
                    } else {
367
                        return "<input type='checkbox' class='checkin' id='checkin_" + oObj.itemnumber + "' name='checkin' value='" + oObj.itemnumber +"'></input>";
368
                    }
369
                }
370
            },
371
            {
372
                "visible":  ClaimReturnedLostValue ? true : false,
373
                "orderable":  false,
374
                "data": function ( oObj ) {
375
                    let content = "";
376
377
                    if ( oObj.return_claim_id ) {
378
                      content = '<span class="badge">' + oObj.return_claim_created_on_formatted + '</span>';
379
                    } else if ( ClaimReturnedLostValue ) {
380
                      content = '<a class="btn btn-default btn-xs claim-returned-btn" data-itemnumber="' + oObj.itemnumber + '"><i class="fa fa-exclamation-circle"></i> ' + __("Claim returned") + '</a>';
381
                    } else {
382
                      content = '<a class="btn btn-default btn-xs" disabled="disabled" title="ClaimReturnedLostValue is not set, this feature is disabled"><i class="fa fa-exclamation-circle"></i> ' + __("Claim returned") + '</a>';
383
                    }
384
                    return content;
385
                }
386
            },
387
            {
388
                "visible":  exports_enabled == 1 ? true : false,
389
                "orderable":  false,
390
                "data": function ( oObj ) {
391
                    var s = "<input type='checkbox' name='itemnumbers' value='" + oObj.itemnumber + "' style='visibility:hidden;' />";
392
393
                    s += "<input type='checkbox' class='export' id='export_" + oObj.biblionumber + "' name='biblionumbers' value='" + oObj.biblionumber + "' />";
394
                    return s;
395
                }
396
            }
397
        ],
398
        "footerCallback": function ( nRow, aaData, iStart, iEnd, aiDisplay ) {
399
            var total_charge = 0;
400
            var total_fine  = 0;
401
            var total_price = 0;
402
            for ( var i=0; i < aaData.length; i++ ) {
403
                total_charge += aaData[i]['charge'] * 1;
404
                total_fine += aaData[i]['fine'] * 1;
405
                total_price  += aaData[i]['price'] * 1;
406
            }
407
            $("#totaldue").html(total_charge.format_price() );
408
            $("#totalfine").html(total_fine.format_price() );
409
            $("#totalprice").html(total_price.format_price() );
410
        },
411
        "paging":  false,
412
        "processing":  true,
413
        "serverSide":  false,
414
        "sAjaxSource": '/cgi-bin/koha/svc/checkouts',
415
        "fnServerData": function ( sSource, aoData, fnCallback ) {
416
            aoData.push( { "name": "borrowernumber", "value": borrowernumber } );
417
418
            $.getJSON( sSource, aoData, function (json) {
419
                fnCallback(json)
420
            } );
421
        },
422
        "rowGroup":{
423
            "dataSrc": "issued_today",
424
            "startRender": function ( rows, group ) {
425
                if ( group ) {
426
                    return __("Today's checkouts");
427
                } else {
428
                    return __("Previous checkouts");
429
                }
430
            }
431
        },
432
        "initComplete": function(oSettings, json) {
433
            // Build a summary of checkouts grouped by itemtype
434
            var checkoutsByItype = json.aaData.reduce(function (obj, row) {
435
                obj[row.type_for_stat] = (obj[row.type_for_stat] || 0) + 1;
436
                return obj;
437
            }, {});
438
            var ul = $('<ul>');
439
            Object.keys(checkoutsByItype).sort().forEach(function (itype) {
440
                var li = $('<li>')
441
                    .append($('<strong>').html(itype || __("No itemtype")))
442
                    .append(': ' + checkoutsByItype[itype]);
443
                ul.append(li);
444
            })
445
            $('<details>')
446
                .addClass('checkouts-by-itemtype')
447
                .append($('<summary>').html( __("Number of checkouts by item type") ))
448
                .append(ul)
449
                .insertBefore(oSettings.nTableWrapper)
450
        },
451
    }, table_settings_issues_table);
452
453
    if ( $("#issues-table").length ) {
454
        $("#issues-table_processing").position({
455
            of: $( "#issues-table" ),
456
            collision: "none"
457
        });
458
    }
459
}
460
461
var loadIssuesTableDelayTimeoutId;
462
var barcodefield = $("#barcode");
463
464
$('#issues-table-load-now-button').click(function(){
465
    if ( loadIssuesTableDelayTimeoutId ) clearTimeout(loadIssuesTableDelayTimeoutId);
466
    LoadIssuesTable();
467
    barcodefield.focus();
468
    return false;
469
});
470
471
$(document).ready(function() {
7
472
8
    var onHoldDueDateSet = false;
473
    var onHoldDueDateSet = false;
9
474
Lines 271-282 $(document).ready(function() { Link Here
271
        }
736
        }
272
        barcodefield.focus();
737
        barcodefield.focus();
273
    });
738
    });
274
    $('#issues-table-load-now-button').click(function(){
275
        if ( loadIssuesTableDelayTimeoutId ) clearTimeout(loadIssuesTableDelayTimeoutId);
276
        LoadIssuesTable();
277
        barcodefield.focus();
278
        return false;
279
    });
280
739
281
    if ( Cookies.get("issues-table-load-immediately-" + script) == "true" ) {
740
    if ( Cookies.get("issues-table-load-immediately-" + script) == "true" ) {
282
        if ( LoadCheckoutsTableDelay ) {
741
        if ( LoadCheckoutsTableDelay ) {
Lines 292-754 $(document).ready(function() { Link Here
292
        Cookies.set("issues-table-load-immediately-" + script, $(this).is(':checked'), { expires: 365, sameSite: 'Lax'  });
751
        Cookies.set("issues-table-load-immediately-" + script, $(this).is(':checked'), { expires: 365, sameSite: 'Lax'  });
293
    });
752
    });
294
753
295
    function RefreshIssuesTable() {
296
        var table = $('#issues-table').DataTable();
297
        var renewchecked = $('input[name=renew]:checked').map(function(){
298
            return this.value;
299
        }).get();
300
        var checkinchecked = $('input[name=checkin]:checked').map(function(){
301
            return this.value;
302
        }).get();
303
        table.ajax.reload( function() {
304
            $('#RenewChecked, #CheckinChecked').prop('disabled' , true );
305
            if ( renewchecked.length ) {
306
                $('#RenewChecked').prop('disabled' , false );
307
                renewchecked.forEach( function(checked) {
308
                    $('.renew[value="'+checked+'"]').prop('checked' , true );
309
                });
310
            }
311
            if ( checkinchecked.length ) {
312
                $('#CheckinChecked').prop('disabled' , false );
313
                checkinchecked.forEach( function(checked) {
314
                    $('.checkin[value="'+checked+'"]').prop('checked' , true );
315
                });
316
            }
317
        var checkout_count = table.page.info().recordsTotal;
318
        $('.checkout_count').text(checkout_count);
319
        });
320
    }
321
322
    function LoadIssuesTable() {
323
        $('#issues-table-loading-message').hide();
324
        $('#issues-table').show();
325
        $('#issues-table-actions').show();
326
        var msg_loading = __('Loading... you may continue scanning.');
327
        issuesTable = KohaTable("issues-table", {
328
            "language":  {
329
                "emptyTable":  msg_loading,
330
                "processing": msg_loading,
331
            },
332
            "autoWidth":  false,
333
            "dom": '<"table_controls"B>rt',
334
            "columns":  [
335
                {
336
                    "data": function( oObj ) {
337
                        return oObj.sort_order;
338
                    }
339
                },
340
                {
341
                    "data": function( oObj ) {
342
                        if ( oObj.issued_today ) {
343
                            return "<strong>" + __("Today's checkouts") + "</strong>";
344
                        } else {
345
                            return "<strong>" + __("Previous checkouts") + "</strong>";
346
                        }
347
                    }
348
                },
349
                {
350
                    "data": "date_due",
351
                    "visible":  false,
352
                },
353
                {
354
                    "orderData":  2, // Sort on hidden unformatted date due column
355
                    "data": function( oObj ) {
356
                        let date_due_formatted = $datetime(oObj.date_due, { as_due_date: true, no_tz_adjust: true });
357
                        var due = oObj.date_due_overdue
358
                            ? "<span class='overdue'>" + date_due_formatted + "</span>"
359
                            : date_due_formatted;
360
361
                        due = "<span id='date_due_" + oObj.itemnumber + "' class='date_due'>" + due + "</span>";
362
363
                        if ( oObj.lost && oObj.claims_returned ) {
364
                            due += "<span class='lost claims_returned'>" + oObj.lost.escapeHtml() + "</span>";
365
                        } else if ( oObj.lost ) {
366
                            due += "<span class='lost'>" + oObj.lost.escapeHtml() + "</span>";
367
                        }
368
369
                        if ( oObj.damaged ) {
370
                            due += "<span class='dmg'>" + oObj.damaged.escapeHtml() + "</span>";
371
                        }
372
373
                        var patron_note = " <span class='patron_note_" + oObj.itemnumber + "'></span>";
374
                        due +="<br>" + patron_note;
375
376
                        return due;
377
                    }
378
                },
379
                {
380
                    "data": function ( oObj ) {
381
                        let title = "<span id='title_" + oObj.itemnumber + "' class='strong'><a href='/cgi-bin/koha/catalogue/detail.pl?biblionumber="
382
                              + oObj.biblionumber
383
                              + "'>"
384
                              + (oObj.title ? oObj.title.escapeHtml() : '' );
385
386
                        $.each(oObj.subtitle, function( index, value ) {
387
                                  title += " " + value.escapeHtml();
388
                        });
389
390
                        title += " " + oObj.part_number + " " + oObj.part_name;
391
392
                        if ( oObj.enumchron ) {
393
                            title += " <span class='item_enumeration'>(" + oObj.enumchron.escapeHtml() + ")</span>";
394
                        }
395
396
                        title += "</a></span>";
397
398
                        if ( oObj.author ) {
399
                            title += " " + __("by _AUTHOR_").replace( "_AUTHOR_",  " " + oObj.author.escapeHtml() );
400
                        }
401
402
                        if ( oObj.itemnotes ) {
403
                            var span_class = "text-muted";
404
                            if ( flatpickr.formatDate( new Date(oObj.issuedate), "Y-m-d" ) == ymd ){
405
                                span_class = "circ-hlt";
406
                            }
407
                            title += "<span class='divider-dash'> - </span><span class='" + span_class + " item-note-public'>" + oObj.itemnotes.escapeHtml() + "</span>";
408
                        }
409
410
                        if ( oObj.itemnotes_nonpublic ) {
411
                            var span_class = "text-danger";
412
                            if ( flatpickr.formatDate( new Date(oObj.issuedate), "Y-m-d" ) == ymd ){
413
                                span_class = "circ-hlt";
414
                            }
415
                            title += "<span class='divider-dash'> - </span><span class='" + span_class + " item-note-nonpublic'>" + oObj.itemnotes_nonpublic.escapeHtml() + "</span>";
416
                        }
417
418
                        var onsite_checkout = '';
419
                        if ( oObj.onsite_checkout == 1 ) {
420
                            onsite_checkout += " <span class='onsite_checkout'>(" + __("On-site checkout") + ")</span>";
421
                        }
422
423
                        if ( oObj.recalled == 1 ) {
424
                             title += "<span class='divider-dash'> - </span><span class='circ-hlt item-recalled'>" +  __("This item has been recalled and the due date updated") + ".</span>";
425
                        }
426
427
                        title += " "
428
                              + "<a href='/cgi-bin/koha/catalogue/moredetail.pl?biblionumber="
429
                              + oObj.biblionumber
430
                              + "&itemnumber="
431
                              + oObj.itemnumber
432
                              + "#"
433
                              + oObj.itemnumber
434
                              + "'>"
435
                              + (oObj.barcode ? oObj.barcode.escapeHtml() : "")
436
                              + "</a>"
437
                              + onsite_checkout
438
439
                        return title;
440
                    },
441
                    "type":  "anti-the"
442
                },
443
                {
444
                    "data": function ( oObj ) {
445
                        return oObj.recordtype_description.escapeHtml();
446
                    }
447
                },
448
                {
449
                    "data": function ( oObj ) {
450
                        return oObj.itemtype_description.escapeHtml();
451
                    }
452
                },
453
                {
454
                    "data": function ( oObj ) {
455
                        return ( oObj.collection ? oObj.collection.escapeHtml() : '' );
456
                    }
457
                },
458
                {
459
                    "data": function ( oObj ) {
460
                        return ( oObj.location ? oObj.location.escapeHtml() : '' );
461
                    }
462
                },
463
                {
464
                    "data": function ( oObj ) {
465
                        return (oObj.homebranch ? oObj.homebranch.escapeHtml() : '' );
466
                    }
467
                },
468
                {
469
                    "data": "issuedate",
470
                    "visible":  false,
471
                },
472
                {
473
                    "orderData":  10, // Sort on hidden unformatted issuedate column
474
                    "data": function( oObj ) {
475
                        return $datetime(oObj.issuedate, { no_tz_adjust: true });
476
                    }
477
                },
478
                {
479
                    "data": function ( oObj ) {
480
                        return (oObj.branchname ? oObj.branchname.escapeHtml() : '' );
481
                    }
482
                },
483
                {
484
                    "data": function ( oObj ) {
485
                        return ( oObj.itemcallnumber ? oObj.itemcallnumber.escapeHtml() : '' );
486
                    }
487
                },
488
                {
489
                    "data": function ( oObj ) {
490
                        return ( oObj.copynumber ? oObj.copynumber.escapeHtml() : '' );
491
                    }
492
                },
493
                {
494
                    "data": function ( oObj ) {
495
                        if ( ! oObj.charge ) oObj.charge = 0;
496
                        return '<span style="text-align: right; display: block;">' + parseFloat(oObj.charge).format_price() + '<span>';
497
                    },
498
                    "className": "nowrap"
499
                },
500
                {
501
                    "data": function ( oObj ) {
502
                        if ( ! oObj.fine ) oObj.fine = 0;
503
                        return '<span style="text-align: right; display: block;">' + parseFloat(oObj.fine).format_price()   + '<span>';
504
                    },
505
                    "className": "nowrap"
506
                },
507
                {
508
                    "data": function ( oObj ) {
509
                        if ( ! oObj.price ) oObj.price = 0;
510
                        return '<span style="text-align: right; display: block;">' + parseFloat(oObj.price).format_price()  + '<span>';
511
                    },
512
                    "className": "nowrap"
513
                },
514
                {
515
                    "orderable":  false,
516
                    "visible":  AllowCirculate ? true : false,
517
                    "data": function ( oObj ) {
518
                        var content = "";
519
                        var msg = "";
520
                        var span_style = "";
521
                        var span_class = "";
522
523
                        if ( oObj.can_renew ) {
524
                            // Do nothing
525
                        } else if ( oObj.can_renew_error == "recalled" ) {
526
                            msg += "<span>"
527
                                    + "<a href='/cgi-bin/koha/recalls/request.pl?biblionumber=" + oObj.biblionumber + "'>" + __("Recalled") + "</a>"
528
                                    + "</span>";
529
530
                            span_style = "display: none";
531
                            span_class = "renewals-allowed-recalled";
532
                        } else if ( oObj.can_renew_error == "on_reserve" ) {
533
                            msg += "<span>"
534
                                    +"<a href='/cgi-bin/koha/reserve/request.pl?biblionumber=" + oObj.biblionumber + "'>" + __("On hold") + "</a>"
535
                                    + "</span>";
536
537
                            span_style = "display: none";
538
                            span_class = "renewals-allowed-on_reserve";
539
                        } else if ( oObj.can_renew_error == "too_many" ) {
540
                            msg += "<span class='renewals-disabled'>"
541
                                    + __("Not renewable")
542
                                    + "</span>";
543
544
                            span_style = "display: none";
545
                            span_class = "renewals-allowed";
546
                        } else if ( oObj.can_renew_error == "too_unseen" ) {
547
                            msg += "<span>"
548
                                    + __("Must be renewed at the library")
549
                                    + "</span>";
550
                            span_class = "renewals-allowed";
551
                        } else if ( oObj.can_renew_error == "restriction" ) {
552
                            msg += "<span class='renewals-disabled'>"
553
                                    + __("Not allowed: patron restricted")
554
                                    + "</span>";
555
556
                            span_style = "display: none";
557
                            span_class = "renewals-allowed";
558
                        } else if ( oObj.can_renew_error == "overdue" ) {
559
                            msg += "<span class='renewals-disabled'>"
560
                                    + __("Not allowed: overdue")
561
                                    + "</span>";
562
563
                            span_style = "display: none";
564
                            span_class = "renewals-allowed";
565
                        } else if ( oObj.can_renew_error == "too_soon" ) {
566
                            msg += "<span class='renewals-disabled'>"
567
                                    + __("No renewal before %s").format(oObj.can_renew_date)
568
                                    + "</span>";
569
570
                            span_style = "display: none";
571
                            span_class = "renewals-allowed";
572
                        } else if ( oObj.can_renew_error == "auto_too_late" ) {
573
                            msg += "<span class='renewals-disabled'>"
574
                                    + __("Can no longer be auto-renewed - number of checkout days exceeded")
575
                                    + "</span>";
576
577
                            span_style = "display: none";
578
                            span_class = "renewals-allowed";
579
                        } else if ( oObj.can_renew_error == "auto_too_much_oweing" ) {
580
                            msg += "<span class='renewals-disabled'>"
581
                                    + __("Automatic renewal failed, patron has unpaid fines")
582
                                    + "</span>";
583
584
                            span_style = "display: none";
585
                            span_class = "renewals-allowed";
586
                        } else if ( oObj.can_renew_error == "auto_account_expired" ) {
587
                            msg += "<span class='renewals-disabled'>"
588
                                    + __("Automatic renewal failed, account expired")
589
                                    + "</span>";
590
591
                            span_style = "display: none";
592
                            span_class = "renewals-allowed";
593
                        } else if ( oObj.can_renew_error == "onsite_checkout" ) {
594
                            // Don't display something if it's an onsite checkout
595
                        } else if ( oObj.can_renew_error == "item_denied_renewal" ) {
596
                            content += "<span class='renewals-disabled'>"
597
                                    + __("Renewal denied by syspref")
598
                                    + "</span>";
599
600
                            span_style = "display: none";
601
                            span_class = "renewals-allowed";
602
                        } else {
603
                            msg += "<span class='renewals-disabled'>"
604
                                    + oObj.can_renew_error
605
                                    + "</span>";
606
607
                            span_style = "display: none";
608
                            span_class = "renewals-allowed";
609
                        }
610
611
                        var can_force_renew = ( oObj.onsite_checkout == 0 ) &&
612
                            ( oObj.can_renew_error != "on_reserve" || (oObj.can_renew_error == "on_reserve" && AllowRenewalOnHoldOverride))
613
                            ? true : false;
614
                        var can_renew = ( oObj.renewals_remaining > 0 && ( !oObj.can_renew_error || oObj.can_renew_error == "too_unseen" ));
615
                        content += "<span>";
616
                        if ( can_renew || can_force_renew ) {
617
                            content += "<span style='padding: 0 1em;'>" + oObj.renewals_count + "</span>";
618
                            content += "<span class='" + span_class + "' style='" + span_style + "'>"
619
                                    +  "<input type='checkbox' ";
620
                            if ( oObj.date_due_overdue && can_renew ) {
621
                                content += "checked='checked' ";
622
                            }
623
                            if (oObj.can_renew_error == "on_reserve") {
624
                                content += "data-on-reserve ";
625
                            }
626
                            content += "class='renew' id='renew_" + oObj.itemnumber + "' name='renew' value='" + oObj.itemnumber +"'/>"
627
                                    +  "</span>";
628
                        }
629
                        content += msg;
630
                        if ( can_renew || can_force_renew ) {
631
                            content += "<span class='renewals-info'>(";
632
                            content += __("%s of %s renewals remaining").format(oObj.renewals_remaining, oObj.renewals_allowed);
633
                            if (UnseenRenewals && oObj.unseen_allowed) {
634
                                content += __(" and %s of %s unseen renewals remaining").format(oObj.unseen_remaining, oObj.unseen_allowed);
635
                            }
636
                            content += ")</span>";
637
                        }
638
                        if(oObj.auto_renew){
639
                            content += "<span class='renewals-info'>(";
640
                            content += __("Scheduled for automatic renewal");
641
                            content += ")</span>";
642
                        }
643
644
                        return content;
645
                    }
646
                },
647
                {
648
                    "orderable":  false,
649
                    "visible":  AllowCirculate ? true : false,
650
                    "data": function ( oObj ) {
651
                        if ( oObj.can_renew_error == "recalled" ) {
652
                            return "<a href='/cgi-bin/koha/recalls/request.pl?biblionumber=" + oObj.biblionumber + "'>" + __("Recalled") + "</a>";
653
                        } else if ( oObj.can_renew_error == "on_reserve" ) {
654
                            return "<a href='/cgi-bin/koha/reserve/request.pl?biblionumber=" + oObj.biblionumber + "'>" + __("On hold") + "</a>";
655
                        } else if ( oObj.materials ) {
656
                            return "<input type='checkbox' class='confirm' id='confirm_" + oObj.itemnumber + "' name='confirm' value='" + oObj.itemnumber + "' data-materials='" + oObj.materials.escapeHtml() + "'></input>";
657
                        } else {
658
                            return "<input type='checkbox' class='checkin' id='checkin_" + oObj.itemnumber + "' name='checkin' value='" + oObj.itemnumber +"'></input>";
659
                        }
660
                    }
661
                },
662
                {
663
                    "visible":  ClaimReturnedLostValue ? true : false,
664
                    "orderable":  false,
665
                    "data": function ( oObj ) {
666
                        let content = "";
667
668
                        if ( oObj.return_claim_id ) {
669
                          content = '<span class="badge">' + oObj.return_claim_created_on_formatted + '</span>';
670
                        } else if ( ClaimReturnedLostValue ) {
671
                          content = '<a class="btn btn-default btn-xs claim-returned-btn" data-itemnumber="' + oObj.itemnumber + '"><i class="fa fa-exclamation-circle"></i> ' + __("Claim returned") + '</a>';
672
                        } else {
673
                          content = '<a class="btn btn-default btn-xs" disabled="disabled" title="ClaimReturnedLostValue is not set, this feature is disabled"><i class="fa fa-exclamation-circle"></i> ' + __("Claim returned") + '</a>';
674
                        }
675
                        return content;
676
                    }
677
                },
678
                {
679
                    "visible":  exports_enabled == 1 ? true : false,
680
                    "orderable":  false,
681
                    "data": function ( oObj ) {
682
                        var s = "<input type='checkbox' name='itemnumbers' value='" + oObj.itemnumber + "' style='visibility:hidden;' />";
683
684
                        s += "<input type='checkbox' class='export' id='export_" + oObj.biblionumber + "' name='biblionumbers' value='" + oObj.biblionumber + "' />";
685
                        return s;
686
                    }
687
                }
688
            ],
689
            "footerCallback": function ( nRow, aaData, iStart, iEnd, aiDisplay ) {
690
                var total_charge = 0;
691
                var total_fine  = 0;
692
                var total_price = 0;
693
                for ( var i=0; i < aaData.length; i++ ) {
694
                    total_charge += aaData[i]['charge'] * 1;
695
                    total_fine += aaData[i]['fine'] * 1;
696
                    total_price  += aaData[i]['price'] * 1;
697
                }
698
                $("#totaldue").html(total_charge.format_price() );
699
                $("#totalfine").html(total_fine.format_price() );
700
                $("#totalprice").html(total_price.format_price() );
701
            },
702
            "paging":  false,
703
            "processing":  true,
704
            "serverSide":  false,
705
            "sAjaxSource": '/cgi-bin/koha/svc/checkouts',
706
            "fnServerData": function ( sSource, aoData, fnCallback ) {
707
                aoData.push( { "name": "borrowernumber", "value": borrowernumber } );
708
709
                $.getJSON( sSource, aoData, function (json) {
710
                    fnCallback(json)
711
                } );
712
            },
713
            "rowGroup":{
714
                "dataSrc": "issued_today",
715
                "startRender": function ( rows, group ) {
716
                    if ( group ) {
717
                        return __("Today's checkouts");
718
                    } else {
719
                        return __("Previous checkouts");
720
                    }
721
                }
722
            },
723
            "initComplete": function(oSettings, json) {
724
                // Build a summary of checkouts grouped by itemtype
725
                var checkoutsByItype = json.aaData.reduce(function (obj, row) {
726
                    obj[row.type_for_stat] = (obj[row.type_for_stat] || 0) + 1;
727
                    return obj;
728
                }, {});
729
                var ul = $('<ul>');
730
                Object.keys(checkoutsByItype).sort().forEach(function (itype) {
731
                    var li = $('<li>')
732
                        .append($('<strong>').html(itype || __("No itemtype")))
733
                        .append(': ' + checkoutsByItype[itype]);
734
                    ul.append(li);
735
                })
736
                $('<details>')
737
                    .addClass('checkouts-by-itemtype')
738
                    .append($('<summary>').html( __("Number of checkouts by item type") ))
739
                    .append(ul)
740
                    .insertBefore(oSettings.nTableWrapper)
741
            },
742
        }, table_settings_issues_table);
743
744
        if ( $("#issues-table").length ) {
745
            $("#issues-table_processing").position({
746
                of: $( "#issues-table" ),
747
                collision: "none"
748
            });
749
        }
750
    }
751
752
    // Don't load relatives' issues table unless it is clicked on
754
    // Don't load relatives' issues table unless it is clicked on
753
    var relativesIssuesTable;
755
    var relativesIssuesTable;
754
    $("#relatives-issues-tab").click( function() {
756
    $("#relatives-issues-tab").click( function() {
755
- 

Return to bug 35506