41c3562a6762288d2198f7d1f1eff833db86a0d0
[koha.git] / koha-tmpl / intranet-tmpl / prog / js / checkouts.js
1 /* global PATRON_NOTE */
2
3 $(document).ready(function() {
4     $.ajaxSetup ({ cache: false });
5
6     var barcodefield = $("#barcode");
7
8     var onHoldDueDateSet = false;
9
10     var onHoldChecked = function() {
11         var isChecked = false;
12         $('input[data-on-reserve]').each(function() {
13             if ($(this).is(':checked')) {
14                 isChecked=true;
15             }
16         });
17         return isChecked;
18     };
19
20     var showHideOnHoldRenewal = function() {
21         // Display the date input
22         if (onHoldChecked()) {
23             $('#newonholdduedate').show()
24         } else {
25             $('#newonholdduedate').hide();
26         }
27     };
28
29     // Handle the select all/none links for checkouts table columns
30     $("#CheckAllRenewals").on("click",function(){
31         $("#UncheckAllCheckins").click();
32         $(".renew:visible").prop("checked", true);
33         showHideOnHoldRenewal();
34         return false;
35     });
36     $("#UncheckAllRenewals").on("click",function(){
37         $(".renew:visible").prop("checked", false);
38         showHideOnHoldRenewal();
39         return false;
40     });
41
42     $("#CheckAllCheckins").on("click",function(){
43         $("#UncheckAllRenewals").click();
44         $(".checkin:visible").prop("checked", true);
45         return false;
46     });
47     $("#UncheckAllCheckins").on("click",function(){
48         $(".checkin:visible").prop("checked", false);
49         return false;
50     });
51
52     $("#newduedate").on("change", function() {
53         if (!onHoldDueDateSet) {
54             $('#newonholdduedate input').val($('#newduedate').val());
55         }
56     });
57
58     $("#newonholdduedate").on("change", function() {
59         onHoldDueDateSet = true;
60     });
61
62     // Don't allow both return and renew checkboxes to be checked
63     $(document).on("change", '.renew', function(){
64         if ( $(this).is(":checked") ) {
65             $( "#checkin_" + $(this).val() ).prop("checked", false);
66         }
67     });
68     $(document).on("change", '.checkin', function(){
69         if ( $(this).is(":checked") ) {
70             $( "#renew_" + $(this).val() ).prop("checked", false);
71         }
72     });
73
74     // Display on hold due dates input when an on hold item is
75     // selected
76     $(document).on('change', '.renew', function(){
77         showHideOnHoldRenewal();
78     });
79
80     $("#output_format > option:first-child").attr("selected", "selected");
81     $("select[name='csv_profile_id']").hide();
82     $(document).on("change", '#issues-table-output-format', function(){
83         if ( $(this).val() == 'csv' ) {
84             $("select[name='csv_profile_id']").show();
85         } else {
86             $("select[name='csv_profile_id']").hide();
87         }
88     });
89
90     // Clicking the table cell checks the checkbox inside it
91     $(document).on("click", 'td', function(e){
92         if(e.target.tagName.toLowerCase() == 'td'){
93           $(this).find("input:checkbox:visible").each( function() {
94             $(this).click();
95           });
96         }
97     });
98
99     // Handle renewals and returns
100     $("#RenewCheckinChecked").on("click",function(){
101         $(".checkin:checked:visible").each(function() {
102             itemnumber = $(this).val();
103
104             $(this).replaceWith("<img id='checkin_" + itemnumber + "' src='" + interface + "/" + theme + "/img/spinner-small.gif' />");
105
106             params = {
107                 itemnumber:     itemnumber,
108                 borrowernumber: borrowernumber,
109                 branchcode:     branchcode,
110                 exempt_fine:    $("#exemptfine").is(':checked')
111             };
112
113             $.post( "/cgi-bin/koha/svc/checkin", params, function( data ) {
114                 id = "#checkin_" + data.itemnumber;
115
116                 content = "";
117                 if ( data.returned ) {
118                     content = CIRCULATION_RETURNED;
119                     $(id).parent().parent().addClass('ok');
120                     $('#date_due_' + data.itemnumber).html(CIRCULATION_RETURNED);
121                     if ( data.patronnote != null ) {
122                         $('.patron_note_' + data.itemnumber).html( PATRON_NOTE + ": " + data.patronnote);
123                     }
124                 } else {
125                     content = CIRCULATION_NOT_RETURNED;
126                     $(id).parent().parent().addClass('warn');
127                 }
128
129                 $(id).replaceWith( content );
130             }, "json")
131         });
132
133         $(".renew:checked:visible").each(function() {
134             var override_limit = $("#override_limit").is(':checked') ? 1 : 0;
135
136             var isOnReserve = $(this).data().hasOwnProperty('onReserve');
137
138             var itemnumber = $(this).val();
139
140             $(this).parent().parent().replaceWith("<img id='renew_" + itemnumber + "' src='" + interface + "/" + theme + "/img/spinner-small.gif' />");
141
142             var params = {
143                 itemnumber:      itemnumber,
144                 borrowernumber:  borrowernumber,
145                 branchcode:      branchcode,
146                 override_limit:  override_limit,
147             };
148
149             // Determine which due date we need to use
150             var dueDate = isOnReserve ?
151                 $("#newonholdduedate input").val() :
152                 $("#newduedate").val();
153
154             if (dueDate && dueDate.length > 0) {
155                 params.date_due = dueDate
156             }
157
158             $.post( "/cgi-bin/koha/svc/renew", params, function( data ) {
159                 var id = "#renew_" + data.itemnumber;
160
161                 var content = "";
162                 if ( data.renew_okay ) {
163                     content = CIRCULATION_RENEWED_DUE + " " + data.date_due;
164                     $('#date_due_' + data.itemnumber).replaceWith( data.date_due );
165                 } else {
166                     content = CIRCULATION_RENEW_FAILED + " ";
167                     if ( data.error == "no_checkout" ) {
168                         content += NOT_CHECKED_OUT;
169                     } else if ( data.error == "too_many" ) {
170                         content += TOO_MANY_RENEWALS;
171                     } else if ( data.error == "on_reserve" ) {
172                         content += ON_RESERVE;
173                     } else if ( data.error == "restriction" ) {
174                         content += NOT_RENEWABLE_RESTRICTION;
175                     } else if ( data.error == "overdue" ) {
176                         content += NOT_RENEWABLE_OVERDUE;
177                     } else if ( data.error ) {
178                         content += data.error;
179                     } else {
180                         content += REASON_UNKNOWN;
181                     }
182                 }
183
184                 $(id).replaceWith( content );
185             }, "json")
186         });
187
188         // Refocus on barcode field if it exists
189         if ( $("#barcode").length ) {
190             $("#barcode").focus();
191         }
192
193         // Prevent form submit
194         return false;
195     });
196
197     $("#RenewAll").on("click",function(){
198         $("#CheckAllRenewals").click();
199         $("#UncheckAllCheckins").click();
200         showHideOnHoldRenewal();
201         $("#RenewCheckinChecked").click();
202
203         // Prevent form submit
204         return false;
205     });
206
207     var ymd = $.datepicker.formatDate('yy-mm-dd', new Date());
208
209     $('#issues-table').hide();
210     $('#issues-table-actions').hide();
211     $('#issues-table-load-immediately').change(function(){
212         if ( this.checked && typeof issuesTable === 'undefined') {
213             $('#issues-table-load-now-button').click();
214         }
215         barcodefield.focus();
216     });
217     $('#issues-table-load-now-button').click(function(){
218         LoadIssuesTable();
219         barcodefield.focus();
220         return false;
221     });
222
223     if ( Cookies.get("issues-table-load-immediately-" + script) == "true" ) {
224         LoadIssuesTable();
225         $('#issues-table-load-immediately').prop('checked', true);
226     }
227     $('#issues-table-load-immediately').on( "change", function(){
228         Cookies.set("issues-table-load-immediately-" + script, $(this).is(':checked'), { expires: 365 });
229     });
230
231     function LoadIssuesTable() {
232         $('#issues-table-loading-message').hide();
233         $('#issues-table').show();
234         $('#issues-table-actions').show();
235
236         var msg_loading = __('Loading... you may continue scanning.');
237         issuesTable = KohaTable("issues-table", {
238             "oLanguage": {
239                 "sEmptyTable" : msg_loading,
240                 "sProcessing": msg_loading,
241             },
242             "bAutoWidth": false,
243             "dom": 'B<"clearfix">rt',
244             "aoColumns": [
245                 {
246                     "mDataProp": function( oObj ) {
247                         return oObj.sort_order;
248                     }
249                 },
250                 {
251                     "mDataProp": function( oObj ) {
252                         if ( oObj.issued_today ) {
253                             return "<strong>" + TODAYS_CHECKOUTS + "</strong>";
254                         } else {
255                             return "<strong>" + PREVIOUS_CHECKOUTS + "</strong>";
256                         }
257                     }
258                 },
259                 {
260                     "mDataProp": "date_due",
261                     "bVisible": false,
262                 },
263                 {
264                     "iDataSort": 2, // Sort on hidden unformatted date due column
265                     "mDataProp": function( oObj ) {
266                         var due = oObj.date_due_formatted;
267
268                         if ( oObj.date_due_overdue ) {
269                             due = "<span class='overdue'>" + due + "</span>";
270                         }
271
272                         due = "<span id='date_due_" + oObj.itemnumber + "' class='date_due'>" + due + "</span>";
273
274                         if ( oObj.lost && oObj.claims_returned ) {
275                             due += "<span class='lost claims_returned'>" + oObj.lost.escapeHtml() + "</span>";
276                         } else if ( oObj.lost ) {
277                             due += "<span class='lost'>" + oObj.lost.escapeHtml() + "</span>";
278                         }
279
280                         if ( oObj.damaged ) {
281                             due += "<span class='dmg'>" + oObj.damaged.escapeHtml() + "</span>";
282                         }
283
284                         var patron_note = " <span class='patron_note_" + oObj.itemnumber + "'></span>";
285                         due +="<br>" + patron_note;
286
287                         return due;
288                     }
289                 },
290                 {
291                     "mDataProp": function ( oObj ) {
292                         let title = "<span id='title_" + oObj.itemnumber + "' class='strong'><a href='/cgi-bin/koha/catalogue/detail.pl?biblionumber="
293                               + oObj.biblionumber
294                               + "'>"
295                               + (oObj.title ? oObj.title.escapeHtml() : '' );
296
297                         $.each(oObj.subtitle, function( index, value ) {
298                                   title += " " + value.escapeHtml();
299                         });
300
301                         title += " " + oObj.part_number + " " + oObj.part_name;
302
303                         if ( oObj.enumchron ) {
304                             title += " (" + oObj.enumchron.escapeHtml() + ")";
305                         }
306
307                         title += "</a></span>";
308
309                         if ( oObj.author ) {
310                             title += " " + BY.replace( "_AUTHOR_",  " " + oObj.author.escapeHtml() );
311                         }
312
313                         if ( oObj.itemnotes ) {
314                             var span_class = "text-muted";
315                             if ( $.datepicker.formatDate('yy-mm-dd', new Date(oObj.issuedate) ) == ymd ) {
316                                 span_class = "circ-hlt";
317                             }
318                             title += " - <span class='" + span_class + " item-note-public'>" + oObj.itemnotes.escapeHtml() + "</span>";
319                         }
320
321                         if ( oObj.itemnotes_nonpublic ) {
322                             var span_class = "text-danger";
323                             if ( $.datepicker.formatDate('yy-mm-dd', new Date(oObj.issuedate) ) == ymd ) {
324                                 span_class = "circ-hlt";
325                             }
326                             title += " - <span class='" + span_class + " item-note-nonpublic'>" + oObj.itemnotes_nonpublic.escapeHtml() + "</span>";
327                         }
328
329                         var onsite_checkout = '';
330                         if ( oObj.onsite_checkout == 1 ) {
331                             onsite_checkout += " <span class='onsite_checkout'>(" + INHOUSE_USE + ")</span>";
332                         }
333
334                         title += " "
335                               + "<a href='/cgi-bin/koha/catalogue/moredetail.pl?biblionumber="
336                               + oObj.biblionumber
337                               + "&itemnumber="
338                               + oObj.itemnumber
339                               + "#"
340                               + oObj.itemnumber
341                               + "'>"
342                               + (oObj.barcode ? oObj.barcode.escapeHtml() : "")
343                               + "</a>"
344                               + onsite_checkout
345
346                         return title;
347                     },
348                     "sType": "anti-the"
349                 },
350                 {
351                     "mDataProp": function ( oObj ) {
352                         return oObj.recordtype_description.escapeHtml();
353                     }
354                 },
355                 {
356                     "mDataProp": function ( oObj ) {
357                         return oObj.itemtype_description.escapeHtml();
358                     }
359                 },
360                 {
361                     "mDataProp": function ( oObj ) {
362                         return ( oObj.collection ? oObj.collection.escapeHtml() : '' );
363                     }
364                 },
365                 {
366                     "mDataProp": function ( oObj ) {
367                         return ( oObj.location ? oObj.location.escapeHtml() : '' );
368                     }
369                 },
370                 {
371                     "mDataProp": function ( oObj ) {
372                         return (oObj.homebranch ? oObj.homebranch.escapeHtml() : '' );
373                     }
374                 },
375                 {
376                     "mDataProp": "issuedate",
377                     "bVisible": false,
378                 },
379                 {
380                     "iDataSort": 10, // Sort on hidden unformatted issuedate column
381                     "mDataProp": "issuedate_formatted",
382                 },
383                 {
384                     "mDataProp": function ( oObj ) {
385                         return (oObj.branchname ? oObj.branchname.escapeHtml() : '' );
386                     }
387                 },
388                 {
389                     "mDataProp": function ( oObj ) {
390                         return ( oObj.itemcallnumber ? oObj.itemcallnumber.escapeHtml() : '' );
391                     }
392                 },
393                 {
394                     "mDataProp": function ( oObj ) {
395                         if ( ! oObj.charge ) oObj.charge = 0;
396                         return '<span style="text-align: right; display: block;">' + parseFloat(oObj.charge).toFixed(2) + '<span>';
397                     }
398                 },
399                 {
400                     "mDataProp": function ( oObj ) {
401                         if ( ! oObj.fine ) oObj.fine = 0;
402                         return '<span style="text-align: right; display: block;">' + parseFloat(oObj.fine).toFixed(2)  + '<span>';
403                     }
404                 },
405                 {
406                     "mDataProp": function ( oObj ) {
407                         if ( ! oObj.price ) oObj.price = 0;
408                         return '<span style="text-align: right; display: block;">' + parseFloat(oObj.price).toFixed(2) + '<span>';
409                     }
410                 },
411                 {
412                     "bSortable": false,
413                     "bVisible": AllowCirculate ? true : false,
414                     "mDataProp": function ( oObj ) {
415                         var content = "";
416                         var msg = "";
417                         var span_style = "";
418                         var span_class = "";
419
420                         if ( oObj.can_renew ) {
421                             // Do nothing
422                         } else if ( oObj.can_renew_error == "on_reserve" ) {
423                             msg += "<span>"
424                                     + "<a href='/cgi-bin/koha/reserve/request.pl?biblionumber=" + oObj.biblionumber + "'>" + ON_HOLD + "</a>"
425                                     + "</span>";
426
427                             span_style = "display: none";
428                             span_class = "renewals-allowed-on_reserve";
429                         } else if ( oObj.can_renew_error == "too_many" ) {
430                             msg += "<span class='renewals-disabled'>"
431                                     + NOT_RENEWABLE
432                                     + "</span>";
433
434                             span_style = "display: none";
435                             span_class = "renewals-allowed";
436                         } else if ( oObj.can_renew_error == "restriction" ) {
437                             msg += "<span class='renewals-disabled'>"
438                                     + NOT_RENEWABLE_RESTRICTION
439                                     + "</span>";
440
441                             span_style = "display: none";
442                             span_class = "renewals-allowed";
443                         } else if ( oObj.can_renew_error == "overdue" ) {
444                             msg += "<span class='renewals-disabled'>"
445                                     + NOT_RENEWABLE_OVERDUE
446                                     + "</span>";
447
448                             span_style = "display: none";
449                             span_class = "renewals-allowed";
450                         } else if ( oObj.can_renew_error == "too_soon" ) {
451                             msg += "<span class='renewals-disabled'>"
452                                     + NOT_RENEWABLE_TOO_SOON.format( oObj.can_renew_date )
453                                     + "</span>";
454
455                             span_style = "display: none";
456                             span_class = "renewals-allowed";
457                         } else if ( oObj.can_renew_error == "auto_too_soon" ) {
458                             msg += "<span class='renewals-disabled'>"
459                                     + NOT_RENEWABLE_AUTO_TOO_SOON
460                                     + "</span>";
461
462                             span_style = "display: none";
463                             span_class = "renewals-allowed";
464                         } else if ( oObj.can_renew_error == "auto_too_late" ) {
465                             msg += "<span class='renewals-disabled'>"
466                                     + NOT_RENEWABLE_AUTO_TOO_LATE
467                                     + "</span>";
468
469                             span_style = "display: none";
470                             span_class = "renewals-allowed";
471                         } else if ( oObj.can_renew_error == "auto_too_much_oweing" ) {
472                             msg += "<span class='renewals-disabled'>"
473                                     + NOT_RENEWABLE_AUTO_TOO_MUCH_OWEING
474                                     + "</span>";
475
476                             span_style = "display: none";
477                             span_class = "renewals-allowed";
478                         } else if ( oObj.can_renew_error == "auto_account_expired" ) {
479                             msg += "<span class='renewals-disabled'>"
480                                     + NOT_RENEWABLE_AUTO_ACCOUNT_EXPIRED
481                                     + "</span>";
482
483                             span_style = "display: none";
484                             span_class = "renewals-allowed";
485                         } else if ( oObj.can_renew_error == "auto_renew" ) {
486                             msg += "<span class='renewals-disabled'>"
487                                     + NOT_RENEWABLE_AUTO_RENEW
488                                     + "</span>";
489
490                             span_style = "display: none";
491                             span_class = "renewals-allowed";
492                         } else if ( oObj.can_renew_error == "onsite_checkout" ) {
493                             // Don't display something if it's an onsite checkout
494                         } else if ( oObj.can_renew_error == "item_denied_renewal" ) {
495                             content += "<span class='renewals-disabled'>"
496                                     + NOT_RENEWABLE_DENIED
497                                     + "</span>";
498
499                             span_style = "display: none";
500                             span_class = "renewals-allowed";
501                         } else {
502                             msg += "<span class='renewals-disabled'>"
503                                     + oObj.can_renew_error
504                                     + "</span>";
505
506                             span_style = "display: none";
507                             span_class = "renewals-allowed";
508                         }
509
510                         var can_force_renew = ( oObj.onsite_checkout == 0 ) &&
511                             ( oObj.can_renew_error != "on_reserve" || (oObj.can_renew_error == "on_reserve" && AllowRenewalOnHoldOverride))
512                             ? true : false;
513                         var can_renew = ( oObj.renewals_remaining > 0  && !oObj.can_renew_error );
514                         content += "<span>";
515                         if ( can_renew || can_force_renew ) {
516                             content += "<span style='padding: 0 1em;'>" + oObj.renewals_count + "</span>";
517                             content += "<span class='" + span_class + "' style='" + span_style + "'>"
518                                     +  "<input type='checkbox' ";
519                             if ( oObj.date_due_overdue && can_renew ) {
520                                 content += "checked='checked' ";
521                             }
522                             if (oObj.can_renew_error == "on_reserve") {
523                                 content += "data-on-reserve ";
524                             }
525                             content += "class='renew' id='renew_" + oObj.itemnumber + "' name='renew' value='" + oObj.itemnumber +"'/>"
526                                     +  "</span>";
527                         }
528                         content += msg;
529                         if ( can_renew || can_force_renew ) {
530                             content += "<span class='renewals'>("
531                                     + RENEWALS_REMAINING.format( oObj.renewals_remaining, oObj.renewals_allowed )
532                                     + ")</span>";
533                         }
534
535                         content += "</span>";
536
537                         return content;
538                     }
539                 },
540                 {
541                     "bSortable": false,
542                     "bVisible": AllowCirculate ? true : false,
543                     "mDataProp": function ( oObj ) {
544                         if ( oObj.can_renew_error == "on_reserve" ) {
545                             return "<a href='/cgi-bin/koha/reserve/request.pl?biblionumber=" + oObj.biblionumber + "'>" + ON_HOLD + "</a>";
546                         } else {
547                             return "<input type='checkbox' class='checkin' id='checkin_" + oObj.itemnumber + "' name='checkin' value='" + oObj.itemnumber +"'></input>";
548                         }
549                     }
550                 },
551                 {
552                     "bVisible": ClaimReturnedLostValue ? true : false,
553                     "bSortable": false,
554                     "mDataProp": function ( oObj ) {
555                         let content = "";
556
557                         if ( oObj.return_claim_id ) {
558                           content = '<span class="badge">' + oObj.return_claim_created_on_formatted + '</span>';
559                         } else {
560                           content = '<a class="btn btn-default btn-xs claim-returned-btn" data-itemnumber="' + oObj.itemnumber + '"><i class="fa fa-exclamation-circle"></i>' + RETURN_CLAIMED_MAKE + '</a>';
561                         }
562                         return content;
563                     }
564                 },
565                 {
566                     "bVisible": exports_enabled == 1 ? true : false,
567                     "bSortable": false,
568                     "mDataProp": function ( oObj ) {
569                         var s = "<input type='checkbox' name='itemnumbers' value='" + oObj.itemnumber + "' style='visibility:hidden;' />";
570
571                         s += "<input type='checkbox' class='export' id='export_" + oObj.biblionumber + "' name='biblionumbers' value='" + oObj.biblionumber + "' />";
572                         return s;
573                     }
574                 }
575             ],
576             "fnFooterCallback": function ( nRow, aaData, iStart, iEnd, aiDisplay ) {
577                 var total_charge = 0;
578                 var total_fine  = 0;
579                 var total_price = 0;
580                 for ( var i=0; i < aaData.length; i++ ) {
581                     total_charge += aaData[i]['charge'] * 1;
582                     total_fine += aaData[i]['fine'] * 1;
583                     total_price  += aaData[i]['price'] * 1;
584                 }
585                 $("#totaldue").html(total_charge.toFixed(2));
586                 $("#totalfine").html(total_fine.toFixed(2));
587                 $("#totalprice").html(total_price.toFixed(2));
588             },
589             "bPaginate": false,
590             "bProcessing": true,
591             "bServerSide": false,
592             "sAjaxSource": '/cgi-bin/koha/svc/checkouts',
593             "fnServerData": function ( sSource, aoData, fnCallback ) {
594                 aoData.push( { "name": "borrowernumber", "value": borrowernumber } );
595
596                 $.getJSON( sSource, aoData, function (json) {
597                     fnCallback(json)
598                 } );
599             },
600             "rowGroup":{
601                 "dataSrc": "issued_today",
602                 "startRender": function ( rows, group ) {
603                     if ( group ) {
604                         return TODAYS_CHECKOUTS;
605                     } else {
606                         return PREVIOUS_CHECKOUTS;
607                     }
608                 }
609             },
610             "fnInitComplete": function(oSettings, json) {
611                 // Build a summary of checkouts grouped by itemtype
612                 var checkoutsByItype = json.aaData.reduce(function (obj, row) {
613                     obj[row.type_for_stat] = (obj[row.type_for_stat] || 0) + 1;
614                     return obj;
615                 }, {});
616                 var ul = $('<ul>');
617                 Object.keys(checkoutsByItype).sort().forEach(function (itype) {
618                     var li = $('<li>')
619                         .append($('<strong>').html(itype || MSG_NO_ITEMTYPE))
620                         .append(': ' + checkoutsByItype[itype]);
621                     ul.append(li);
622                 })
623                 $('<details>')
624                     .addClass('checkouts-by-itemtype')
625                     .append($('<summary>').html(MSG_CHECKOUTS_BY_ITEMTYPE))
626                     .append(ul)
627                     .insertBefore(oSettings.nTableWrapper)
628             },
629         }, columns_settings_issues_table);
630
631         if ( $("#issues-table").length ) {
632             $("#issues-table_processing").position({
633                 of: $( "#issues-table" ),
634                 collision: "none"
635             });
636         }
637     }
638
639     // Don't load relatives' issues table unless it is clicked on
640     var relativesIssuesTable;
641     $("#relatives-issues-tab").click( function() {
642         if ( ! relativesIssuesTable ) {
643             relativesIssuesTable = $("#relatives-issues-table").dataTable($.extend(true, {}, dataTablesDefaults, {
644                 "bAutoWidth": false,
645                 "sDom": "rt",
646                 "aaSorting": [],
647                 "aoColumns": [
648                     {
649                         "mDataProp": "date_due",
650                         "bVisible": false,
651                     },
652                     {
653                         "iDataSort": 0, // Sort on hidden unformatted date due column
654                         "mDataProp": function( oObj ) {
655                             var today = new Date();
656                             var due = new Date( oObj.date_due );
657                             if ( today > due ) {
658                                 return "<span class='overdue'>" + oObj.date_due_formatted + "</span>";
659                             } else {
660                                 return oObj.date_due_formatted;
661                             }
662                         }
663                     },
664                     {
665                         "mDataProp": function ( oObj ) {
666                             let title = "<span class='strong'><a href='/cgi-bin/koha/catalogue/detail.pl?biblionumber="
667                                   + oObj.biblionumber
668                                   + "'>"
669                                   + (oObj.title ? oObj.title.escapeHtml() : '' );
670
671                             $.each(oObj.subtitle, function( index, value ) {
672                                       title += " " + value.escapeHtml();
673                             });
674
675                             title += " " + oObj.part_number + " " + oObj.part_name;
676
677                             if ( oObj.enumchron ) {
678                                 title += " (" + oObj.enumchron.escapeHtml() + ")";
679                             }
680
681                             title += "</a></span>";
682
683                             if ( oObj.author ) {
684                                 title += " " + BY.replace( "_AUTHOR_", " " + oObj.author.escapeHtml() );
685                             }
686
687                             if ( oObj.itemnotes ) {
688                                 var span_class = "";
689                                 if ( $.datepicker.formatDate('yy-mm-dd', new Date(oObj.issuedate) ) == ymd ) {
690                                     span_class = "circ-hlt";
691                                 }
692                                 title += " - <span class='" + span_class + "'>" + oObj.itemnotes.escapeHtml() + "</span>"
693                             }
694
695                             if ( oObj.itemnotes_nonpublic ) {
696                                 var span_class = "";
697                                 if ( $.datepicker.formatDate('yy-mm-dd', new Date(oObj.issuedate) ) == ymd ) {
698                                     span_class = "circ-hlt";
699                                 }
700                                 title += " - <span class='" + span_class + "'>" + oObj.itemnotes_nonpublic.escapeHtml() + "</span>"
701                             }
702
703                             var onsite_checkout = '';
704                             if ( oObj.onsite_checkout == 1 ) {
705                                 onsite_checkout += " <span class='onsite_checkout'>(" + INHOUSE_USE + ")</span>";
706                             }
707
708                             title += " "
709                                   + "<a href='/cgi-bin/koha/catalogue/moredetail.pl?biblionumber="
710                                   + oObj.biblionumber
711                                   + "&itemnumber="
712                                   + oObj.itemnumber
713                                   + "#"
714                                   + oObj.itemnumber
715                                   + "'>"
716                                   + (oObj.barcode ? oObj.barcode.escapeHtml() : "")
717                                   + "</a>"
718                                   + onsite_checkout;
719
720                             return title;
721                         },
722                         "sType": "anti-the"
723                     },
724                     {
725                         "mDataProp": function ( oObj ) {
726                             return oObj.recordtype_description.escapeHtml();
727                         }
728                     },
729                     {
730                         "mDataProp": function ( oObj ) {
731                             return oObj.itemtype_description.escapeHtml();
732                         }
733                     },
734                     {
735                         "mDataProp": function ( oObj ) {
736                             return ( oObj.collection ? oObj.collection.escapeHtml() : '' );
737                         }
738                     },
739                     {
740                         "mDataProp": function ( oObj ) {
741                             return ( oObj.location ? oObj.location.escapeHtml() : '' );
742                         }
743                     },
744                     {
745                         "mDataProp": "issuedate",
746                         "bVisible": false,
747                     },
748                     {
749                         "iDataSort": 7, // Sort on hidden unformatted issuedate column
750                         "mDataProp": "issuedate_formatted",
751                     },
752                     {
753                         "mDataProp": function ( oObj ) {
754                             return ( oObj.branchname ? oObj.branchname.escapeHtml() : '' );
755                         }
756                     },
757                     {
758                         "mDataProp": function ( oObj ) {
759                             return ( oObj.itemcallnumber ? oObj.itemcallnumber.escapeHtml() : '' );
760                         }
761                     },
762                     {
763                         "mDataProp": function ( oObj ) {
764                             if ( ! oObj.charge ) oObj.charge = 0;
765                             return parseFloat(oObj.charge).toFixed(2);
766                         }
767                     },
768                     {
769                         "mDataProp": function ( oObj ) {
770                             if ( ! oObj.fine ) oObj.fine = 0;
771                             return parseFloat(oObj.fine).toFixed(2);
772                         }
773                     },
774                     {
775                         "mDataProp": function ( oObj ) {
776                             if ( ! oObj.price ) oObj.price = 0;
777                             return parseFloat(oObj.price).toFixed(2);
778                         }
779                     },
780                     {
781                         "mDataProp": function( oObj ) {
782                             return "<a href='/cgi-bin/koha/members/moremember.pl?borrowernumber=" + oObj.borrowernumber + "'>"
783                                 + oObj.borrower.firstname.escapeHtml()
784                                 + " " +
785                                 oObj.borrower.surname.escapeHtml()
786                                 + " (" + oObj.borrower.cardnumber.escapeHtml() + ")</a>"
787                         }
788                     },
789                 ],
790                 "bPaginate": false,
791                 "bProcessing": true,
792                 "bServerSide": false,
793                 "sAjaxSource": '/cgi-bin/koha/svc/checkouts',
794                 "fnServerData": function ( sSource, aoData, fnCallback ) {
795                     $.each(relatives_borrowernumbers, function( index, value ) {
796                         aoData.push( { "name": "borrowernumber", "value": value } );
797                     });
798
799                     $.getJSON( sSource, aoData, function (json) {
800                         fnCallback(json)
801                     } );
802                 },
803             }));
804         }
805     });
806
807     if ( $("#relatives-issues-table").length ) {
808         $("#relatives-issues-table_processing").position({
809             of: $( "#relatives-issues-table" ),
810             collision: "none"
811         });
812     }
813
814     if ( AllowRenewalLimitOverride || AllowRenewalOnHoldOverride ) {
815         $( '#override_limit' ).click( function () {
816             if ( this.checked ) {
817                 if ( AllowRenewalLimitOverride ) {
818                     $( '.renewals-allowed' ).show();
819                     $( '.renewals-disabled' ).hide();
820                 }
821                 if ( AllowRenewalOnHoldOverride ) {
822                     $( '.renewals-allowed-on_reserve' ).show();
823                 }
824             } else {
825                 $( '.renewals-allowed' ).hide();
826                 $( '.renewals-allowed-on_reserve' ).hide();
827                 $( '.renewals-disabled' ).show();
828             }
829         } ).prop('checked', false);
830     }
831
832     // Handle return claims
833     $(document).on("click", '.claim-returned-btn', function(e){
834         e.preventDefault();
835         itemnumber = $(this).data('itemnumber');
836
837         $('#claims-returned-itemnumber').val(itemnumber);
838         $('#claims-returned-notes').val("");
839         $('#claims-returned-charge-lost-fee').attr('checked', false)
840         $('#claims-returned-modal').modal()
841     });
842     $(document).on("click", '#claims-returned-modal-btn-submit', function(e){
843         let itemnumber = $('#claims-returned-itemnumber').val();
844         let notes = $('#claims-returned-notes').val();
845         let fee = $('#claims-returned-charge-lost-fee').attr('checked') ? true : false;
846
847         $('#claims-returned-modal').modal('hide')
848
849         $('.claim-returned-btn[data-itemnumber="' + itemnumber + '"]').replaceWith('<img id="return_claim_spinner_' + itemnumber + ' src=' + interface + '/' + theme + '/img/spinner-small.gif />');
850
851         params = {
852             item_id: itemnumber,
853             notes: notes,
854             charge_lost_fee: fee,
855             created_by: logged_in_user_borrowernumber,
856         };
857
858         $.post( '/api/v1/return_claims', JSON.stringify(params), function( data ) {
859
860             id = "#return_claim_spinner_" + data.item_id;
861
862             let created_on = new Date(data.created_on);
863
864             let content = "";
865             if ( data.claim_id ) {
866                 content = '<span class="badge">' + created_on.toLocaleDateString() + '</span>';
867                 $(id).parent().parent().addClass('ok');
868             } else {
869                 content = RETURN_CLAIMED_FAILURE;
870                 $(id).parent().parent().addClass('warn');
871             }
872
873             $(id).replaceWith( content );
874
875             refreshReturnClaimsTable();
876         }, "json")
877
878     });
879
880
881     // Don't load return claims table unless it is clicked on
882     var returnClaimsTable;
883     $("#return-claims-tab").click( function() {
884         refreshReturnClaimsTable();
885     });
886
887     function refreshReturnClaimsTable(){
888         loadReturnClaimsTable();
889         $("#return-claims-table").DataTable().ajax.reload();
890     }
891     function loadReturnClaimsTable() {
892         if ( ! returnClaimsTable ) {
893             returnClaimsTable = $("#return-claims-table").dataTable({
894                 "bAutoWidth": false,
895                 "sDom": "rt",
896                 "aaSorting": [],
897                 "aoColumns": [
898                     {
899                         "mDataProp": "id",
900                         "bVisible": false,
901                     },
902                     {
903                         "mDataProp": function ( oObj ) {
904                               let title = '<a class="return-claim-title strong" href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=' + oObj.biblionumber + '">'
905                                   + oObj.title
906                                   + ( oObj.enumchron || "" )
907                               + '</a>';
908                               if ( oObj.author ) {
909                                 title += ' by ' + oObj.author;
910                               }
911                               title += ' <a href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber='
912                                     + oObj.biblionumber
913                                     + '&itemnumber='
914                                     + oObj.itemnumber
915                                     + '">'
916                                     + (oObj.barcode ? oObj.barcode.escapeHtml() : "")
917                                     + '</a>';
918
919                               return title;
920                         }
921                     },
922                     {
923                         "sClass": "return-claim-notes-td",
924                         "mDataProp": function ( oObj ) {
925                             return '<span id="return-claim-notes-static-' + oObj.id + '" class="return-claim-notes" data-return-claim-id="' + oObj.id + '">' + oObj.notes + '</span>'
926                                 + '<i style="float:right" class="fa fa-pencil-square-o" title="' + __("Double click to edit") + '"></i>';
927                         }
928                     },
929                     {
930                         "mDataProp": function ( oObj ) {
931                             let created_on = new Date( oObj.created_on );
932                             return created_on.toLocaleDateString();
933                         }
934                     },
935                     {
936                         "mDataProp": function ( oObj ) {
937                             if ( oObj.updated_on ) {
938                                 let updated_on = new Date( oObj.updated_on );
939                                 return updated_on.toLocaleDateString();
940                             } else {
941                                 return "";
942                             }
943                         }
944                     },
945                     {
946                         "mDataProp": function ( oObj ) {
947                             if ( ! oObj.resolution ) return "";
948
949                             let desc = '<strong>' + oObj.resolution_data.lib + '</strong> <i>(';
950                             if (oObj.resolved_by_data) desc += '<a href="/cgi-bin/koha/circ/circulation.pl?borrowernumber=' + oObj.resolved_by_data.borrowernumber + '">' + ( oObj.resolved_by_data.firstname || "" ) + " " + ( oObj.resolved_by_data.surname || "" ) + '</a>';
951                             desc += ', ' + oObj.resolved_on + ')</i>';
952                             return desc;
953                         }
954                     },
955                     {
956                         "mDataProp": function ( oObj ) {
957                             let delete_html = oObj.resolved_on
958                                 ? '<li><a href="#" class="return-claim-tools-delete" data-return-claim-id="' + oObj.id + '"><i class="fa fa-trash"></i> ' + __("Delete") + '</a></li>'
959                                 : "";
960                             let resolve_html = ! oObj.resolution
961                                 ? '<li><a href="#" class="return-claim-tools-resolve" data-return-claim-id="' + oObj.id + '"><i class="fa fa-check-square"></i> ' + __("Resolve") + '</a></li>'
962                                 : "";
963
964                             return  '<div class="btn-group">'
965                                   + ' <button type="button" class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">'
966                                   + __("Actions") + ' <span class="caret"></span>'
967                                   + ' </button>'
968                                   + ' <ul class="dropdown-menu">'
969                                   + '  <li><a href="#" class="return-claim-tools-editnotes" data-return-claim-id="' + oObj.id + '"><i class="fa fa-edit"></i> ' + __("Edit notes") + '</a></li>'
970                                   + resolve_html
971                                   + delete_html
972                                   + ' </ul>'
973                                   + ' </div>';
974                         }
975                     },
976                 ],
977                 "bPaginate": false,
978                 "bProcessing": true,
979                 "bServerSide": false,
980                 "sAjaxSource": '/cgi-bin/koha/svc/return_claims',
981                 "fnServerData": function ( sSource, aoData, fnCallback ) {
982                     aoData.push( { "name": "borrowernumber", "value": borrowernumber } );
983
984                     $.getJSON( sSource, aoData, function (json) {
985                         let resolved = json.resolved;
986                         let unresolved = json.unresolved;
987
988                         $('#return-claims-count-resolved').text(resolved);
989                         $('#return-claims-count-unresolved').text(unresolved);
990
991                         fnCallback(json)
992                     } );
993                 },
994             });
995         }
996     }
997
998     $('body').on('click', '.return-claim-tools-editnotes', function() {
999         let id = $(this).data('return-claim-id');
1000         $('#return-claim-notes-static-' + id).parent().dblclick();
1001     });
1002     $('body').on('dblclick', '.return-claim-notes-td', function() {
1003         let elt = $(this).children('.return-claim-notes');
1004         let id = elt.data('return-claim-id');
1005         if ( $('#return-claim-notes-editor-textarea-' + id).length == 0 ) {
1006             let note = elt.text();
1007             let editor =
1008                 '  <span id="return-claim-notes-editor-' + id + '">'
1009                 + ' <textarea id="return-claim-notes-editor-textarea-' + id + '">' + note + '</textarea>'
1010                 + ' <br/>'
1011                 + ' <a class="btn btn-default btn-xs claim-returned-notes-editor-submit" data-return-claim-id="' + id + '"><i class="fa fa-save"></i> ' + __("Update") + '</a>'
1012                 + ' <a class="claim-returned-notes-editor-cancel" data-return-claim-id="' + id + '" href="#">' + __("Cancel") + '</a>'
1013                 + '</span>';
1014             elt.hide();
1015             $(editor).insertAfter( elt );
1016         }
1017     });
1018
1019     $('body').on('click', '.claim-returned-notes-editor-submit', function(){
1020         let id = $(this).data('return-claim-id');
1021         let notes = $('#return-claim-notes-editor-textarea-' + id).val();
1022
1023         let params = {
1024             notes: notes,
1025             updated_by: logged_in_user_borrowernumber
1026         };
1027
1028         $(this).parent().remove();
1029
1030         $.ajax({
1031             url: '/api/v1/return_claims/' + id + '/notes',
1032             type: 'PUT',
1033             data: JSON.stringify(params),
1034             success: function( data ) {
1035                 let notes = $('#return-claim-notes-static-' + id);
1036                 notes.text(data.notes);
1037                 notes.show();
1038             },
1039             contentType: "json"
1040         });
1041     });
1042
1043     $('body').on('click', '.claim-returned-notes-editor-cancel', function(){
1044         let id = $(this).data('return-claim-id');
1045         $(this).parent().remove();
1046         $('#return-claim-notes-static-' + id).show();
1047     });
1048
1049     // Hanld return claim deletion
1050     $('body').on('click', '.return-claim-tools-delete', function() {
1051         let confirmed = confirm(CONFIRM_DELETE_RETURN_CLAIM);
1052         if ( confirmed ) {
1053             let id = $(this).data('return-claim-id');
1054
1055             $.ajax({
1056                 url: '/api/v1/return_claims/' + id,
1057                 type: 'DELETE',
1058                 success: function( data ) {
1059                     refreshReturnClaimsTable();
1060                 }
1061             });
1062         }
1063     });
1064
1065     // Handle return claim resolution
1066     $('body').on('click', '.return-claim-tools-resolve', function() {
1067         let id = $(this).data('return-claim-id');
1068
1069         $('#claims-returned-resolved-modal-id').val(id);
1070         $('#claims-returned-resolved-modal').modal()
1071     });
1072
1073     $(document).on('click', '#claims-returned-resolved-modal-btn-submit', function(e) {
1074         let resolution = $('#claims-returned-resolved-modal-resolved-code').val();
1075         let id = $('#claims-returned-resolved-modal-id').val();
1076
1077         $('#claims-returned-resolved-modal-btn-submit-spinner').show();
1078         $('#claims-returned-resolved-modal-btn-submit-icon').hide();
1079
1080         params = {
1081           resolution: resolution,
1082           updated_by: logged_in_user_borrowernumber
1083         };
1084
1085         $.ajax({
1086             url: '/api/v1/return_claims/' + id + '/resolve',
1087             type: 'PUT',
1088             data: JSON.stringify(params),
1089             success: function( data ) {
1090                 $('#claims-returned-resolved-modal-btn-submit-spinner').hide();
1091                 $('#claims-returned-resolved-modal-btn-submit-icon').show();
1092                 $('#claims-returned-resolved-modal').modal('hide')
1093
1094                 refreshReturnClaimsTable();
1095             },
1096             contentType: "json"
1097         });
1098
1099     });
1100
1101  });