169bdc4e36c78d467a842e98c702f1b83d7d4e72
[koha-equinox.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         issuesTable = KohaTable("issues-table", {
237             "oLanguage": {
238                 "sEmptyTable" : MSG_DT_LOADING_RECORDS,
239                 "sProcessing": MSG_DT_LOADING_RECORDS,
240             },
241             "bAutoWidth": false,
242             "dom": 'B<"clearfix">rt',
243             "aoColumns": [
244                 {
245                     "mDataProp": function( oObj ) {
246                         return oObj.sort_order;
247                     }
248                 },
249                 {
250                     "mDataProp": function( oObj ) {
251                         if ( oObj.issued_today ) {
252                             return "<strong>" + TODAYS_CHECKOUTS + "</strong>";
253                         } else {
254                             return "<strong>" + PREVIOUS_CHECKOUTS + "</strong>";
255                         }
256                     }
257                 },
258                 {
259                     "mDataProp": "date_due",
260                     "bVisible": false,
261                 },
262                 {
263                     "iDataSort": 2, // Sort on hidden unformatted date due column
264                     "mDataProp": function( oObj ) {
265                         var due = oObj.date_due_formatted;
266
267                         if ( oObj.date_due_overdue ) {
268                             due = "<span class='overdue'>" + due + "</span>";
269                         }
270
271                         due = "<span id='date_due_" + oObj.itemnumber + "' class='date_due'>" + due + "</span>";
272
273                         if ( oObj.lost && oObj.claims_returned ) {
274                             due += "<span class='lost claims_returned'>" + oObj.lost.escapeHtml() + "</span>";
275                         } else if ( oObj.lost ) {
276                             due += "<span class='lost'>" + oObj.lost.escapeHtml() + "</span>";
277                         }
278
279                         if ( oObj.damaged ) {
280                             due += "<span class='dmg'>" + oObj.damaged.escapeHtml() + "</span>";
281                         }
282
283                         var patron_note = " <span class='patron_note_" + oObj.itemnumber + "'></span>";
284                         due +="<br>" + patron_note;
285
286                         return due;
287                     }
288                 },
289                 {
290                     "mDataProp": function ( oObj ) {
291                         title = "<span id='title_" + oObj.itemnumber + "' class='strong'><a href='/cgi-bin/koha/catalogue/detail.pl?biblionumber="
292                               + oObj.biblionumber
293                               + "'>"
294                               + oObj.title.escapeHtml();
295
296                         $.each(oObj.subtitle, function( index, value ) {
297                                   title += " " + value.escapeHtml();
298                         });
299
300                         title += " " + oObj.part_number + " " + oObj.part_name;
301
302                         if ( oObj.enumchron ) {
303                             title += " (" + oObj.enumchron.escapeHtml() + ")";
304                         }
305
306                         title += "</a></span>";
307
308                         if ( oObj.author ) {
309                             title += " " + BY.replace( "_AUTHOR_",  " " + oObj.author.escapeHtml() );
310                         }
311
312                         if ( oObj.itemnotes ) {
313                             var span_class = "text-muted";
314                             if ( $.datepicker.formatDate('yy-mm-dd', new Date(oObj.issuedate) ) == ymd ) {
315                                 span_class = "circ-hlt";
316                             }
317                             title += " - <span class='" + span_class + " item-note-public'>" + oObj.itemnotes.escapeHtml() + "</span>";
318                         }
319
320                         if ( oObj.itemnotes_nonpublic ) {
321                             var span_class = "text-danger";
322                             if ( $.datepicker.formatDate('yy-mm-dd', new Date(oObj.issuedate) ) == ymd ) {
323                                 span_class = "circ-hlt";
324                             }
325                             title += " - <span class='" + span_class + " item-note-nonpublic'>" + oObj.itemnotes_nonpublic.escapeHtml() + "</span>";
326                         }
327
328                         var onsite_checkout = '';
329                         if ( oObj.onsite_checkout == 1 ) {
330                             onsite_checkout += " <span class='onsite_checkout'>(" + INHOUSE_USE + ")</span>";
331                         }
332
333                         title += " "
334                               + "<a href='/cgi-bin/koha/catalogue/moredetail.pl?biblionumber="
335                               + oObj.biblionumber
336                               + "&itemnumber="
337                               + oObj.itemnumber
338                               + "#"
339                               + oObj.itemnumber
340                               + "'>"
341                               + (oObj.barcode ? oObj.barcode.escapeHtml() : "")
342                               + "</a>"
343                               + onsite_checkout
344
345                         return title;
346                     },
347                     "sType": "anti-the"
348                 },
349                 {
350                     "mDataProp": function ( oObj ) {
351                         return oObj.recordtype_description.escapeHtml();
352                     }
353                 },
354                 {
355                     "mDataProp": function ( oObj ) {
356                         return oObj.itemtype_description.escapeHtml();
357                     }
358                 },
359                 {
360                     "mDataProp": function ( oObj ) {
361                         return ( oObj.collection ? oObj.collection.escapeHtml() : '' );
362                     }
363                 },
364                 {
365                     "mDataProp": function ( oObj ) {
366                         return ( oObj.location ? oObj.location.escapeHtml() : '' );
367                     }
368                 },
369                 {
370                     "mDataProp": function ( oObj ) {
371                         return oObj.homebranch.escapeHtml();
372                     }
373                 },
374                 {
375                     "mDataProp": "issuedate",
376                     "bVisible": false,
377                 },
378                 {
379                     "iDataSort": 9, // Sort on hidden unformatted issuedate column
380                     "mDataProp": "issuedate_formatted",
381                 },
382                 {
383                     "mDataProp": function ( oObj ) {
384                         return oObj.branchname.escapeHtml();
385                     }
386                 },
387                 {
388                     "mDataProp": function ( oObj ) {
389                         return ( oObj.itemcallnumber ? oObj.itemcallnumber.escapeHtml() : '' );
390                     }
391                 },
392                 {
393                     "mDataProp": function ( oObj ) {
394                         if ( ! oObj.charge ) oObj.charge = 0;
395                         return '<span style="text-align: right; display: block;">' + parseFloat(oObj.charge).toFixed(2) + '<span>';
396                     }
397                 },
398                 {
399                     "mDataProp": function ( oObj ) {
400                         if ( ! oObj.fine ) oObj.fine = 0;
401                         return '<span style="text-align: right; display: block;">' + parseFloat(oObj.fine).toFixed(2)  + '<span>';
402                     }
403                 },
404                 {
405                     "mDataProp": function ( oObj ) {
406                         if ( ! oObj.price ) oObj.price = 0;
407                         return '<span style="text-align: right; display: block;">' + parseFloat(oObj.price).toFixed(2) + '<span>';
408                     }
409                 },
410                 {
411                     "bSortable": false,
412                     "bVisible": AllowCirculate ? true : false,
413                     "mDataProp": function ( oObj ) {
414                         var content = "";
415                         var msg = "";
416                         var span_style = "";
417                         var span_class = "";
418
419                         if ( oObj.can_renew ) {
420                             // Do nothing
421                         } else if ( oObj.can_renew_error == "on_reserve" ) {
422                             msg += "<span>"
423                                     + "<a href='/cgi-bin/koha/reserve/request.pl?biblionumber=" + oObj.biblionumber + "'>" + ON_HOLD + "</a>"
424                                     + "</span>";
425
426                             span_style = "display: none";
427                             span_class = "renewals-allowed-on_reserve";
428                         } else if ( oObj.can_renew_error == "too_many" ) {
429                             msg += "<span class='renewals-disabled'>"
430                                     + NOT_RENEWABLE
431                                     + "</span>";
432
433                             span_style = "display: none";
434                             span_class = "renewals-allowed";
435                         } else if ( oObj.can_renew_error == "restriction" ) {
436                             msg += "<span class='renewals-disabled'>"
437                                     + NOT_RENEWABLE_RESTRICTION
438                                     + "</span>";
439
440                             span_style = "display: none";
441                             span_class = "renewals-allowed";
442                         } else if ( oObj.can_renew_error == "overdue" ) {
443                             msg += "<span class='renewals-disabled'>"
444                                     + NOT_RENEWABLE_OVERDUE
445                                     + "</span>";
446
447                             span_style = "display: none";
448                             span_class = "renewals-allowed";
449                         } else if ( oObj.can_renew_error == "too_soon" ) {
450                             msg += "<span class='renewals-disabled'>"
451                                     + NOT_RENEWABLE_TOO_SOON.format( oObj.can_renew_date )
452                                     + "</span>";
453
454                             span_style = "display: none";
455                             span_class = "renewals-allowed";
456                         } else if ( oObj.can_renew_error == "auto_too_soon" ) {
457                             msg += "<span class='renewals-disabled'>"
458                                     + NOT_RENEWABLE_AUTO_TOO_SOON
459                                     + "</span>";
460
461                             span_style = "display: none";
462                             span_class = "renewals-allowed";
463                         } else if ( oObj.can_renew_error == "auto_too_late" ) {
464                             msg += "<span class='renewals-disabled'>"
465                                     + NOT_RENEWABLE_AUTO_TOO_LATE
466                                     + "</span>";
467
468                             span_style = "display: none";
469                             span_class = "renewals-allowed";
470                         } else if ( oObj.can_renew_error == "auto_too_much_oweing" ) {
471                             msg += "<span class='renewals-disabled'>"
472                                     + NOT_RENEWABLE_AUTO_TOO_MUCH_OWEING
473                                     + "</span>";
474
475                             span_style = "display: none";
476                             span_class = "renewals-allowed";
477                         } else if ( oObj.can_renew_error == "auto_account_expired" ) {
478                             msg += "<span class='renewals-disabled'>"
479                                     + NOT_RENEWABLE_AUTO_ACCOUNT_EXPIRED
480                                     + "</span>";
481
482                             span_style = "display: none";
483                             span_class = "renewals-allowed";
484                         } else if ( oObj.can_renew_error == "auto_renew" ) {
485                             msg += "<span class='renewals-disabled'>"
486                                     + NOT_RENEWABLE_AUTO_RENEW
487                                     + "</span>";
488
489                             span_style = "display: none";
490                             span_class = "renewals-allowed";
491                         } else if ( oObj.can_renew_error == "onsite_checkout" ) {
492                             // Don't display something if it's an onsite checkout
493                         } else if ( oObj.can_renew_error == "item_denied_renewal" ) {
494                             content += "<span class='renewals-disabled'>"
495                                     + NOT_RENEWABLE_DENIED
496                                     + "</span>";
497
498                             span_style = "display: none";
499                             span_class = "renewals-allowed";
500                         } else {
501                             msg += "<span class='renewals-disabled'>"
502                                     + oObj.can_renew_error
503                                     + "</span>";
504
505                             span_style = "display: none";
506                             span_class = "renewals-allowed";
507                         }
508
509                         var can_force_renew = ( oObj.onsite_checkout == 0 ) &&
510                             ( oObj.can_renew_error != "on_reserve" || (oObj.can_renew_error == "on_reserve" && AllowRenewalOnHoldOverride))
511                             ? true : false;
512                         var can_renew = ( oObj.renewals_remaining > 0  && !oObj.can_renew_error );
513                         content += "<span>";
514                         if ( can_renew || can_force_renew ) {
515                             content += "<span style='padding: 0 1em;'>" + oObj.renewals_count + "</span>";
516                             content += "<span class='" + span_class + "' style='" + span_style + "'>"
517                                     +  "<input type='checkbox' ";
518                             if ( oObj.date_due_overdue && can_renew ) {
519                                 content += "checked='checked' ";
520                             }
521                             if (oObj.can_renew_error == "on_reserve") {
522                                 content += "data-on-reserve ";
523                             }
524                             content += "class='renew' id='renew_" + oObj.itemnumber + "' name='renew' value='" + oObj.itemnumber +"'/>"
525                                     +  "</span>";
526                         }
527                         content += msg;
528                         if ( can_renew || can_force_renew ) {
529                             content += "<span class='renewals'>("
530                                     + RENEWALS_REMAINING.format( oObj.renewals_remaining, oObj.renewals_allowed )
531                                     + ")</span>";
532                         }
533
534                         content += "</span>";
535
536                         return content;
537                     }
538                 },
539                 {
540                     "bSortable": false,
541                     "bVisible": AllowCirculate ? true : false,
542                     "mDataProp": function ( oObj ) {
543                         if ( oObj.can_renew_error == "on_reserve" ) {
544                             return "<a href='/cgi-bin/koha/reserve/request.pl?biblionumber=" + oObj.biblionumber + "'>" + ON_HOLD + "</a>";
545                         } else {
546                             return "<input type='checkbox' class='checkin' id='checkin_" + oObj.itemnumber + "' name='checkin' value='" + oObj.itemnumber +"'></input>";
547                         }
548                     }
549                 },
550                 {
551                     "bVisible": ClaimReturnedLostValue ? true : false,
552                     "bSortable": false,
553                     "mDataProp": function ( oObj ) {
554                         let content = "";
555
556                         if ( oObj.return_claim_id ) {
557                           content = '<span class="badge">' + oObj.return_claim_created_on_formatted + '</span>';
558                         } else {
559                           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>';
560                         }
561                         return content;
562                     }
563                 },
564                 {
565                     "bVisible": exports_enabled == 1 ? true : false,
566                     "bSortable": false,
567                     "mDataProp": function ( oObj ) {
568                         var s = "<input type='checkbox' name='itemnumbers' value='" + oObj.itemnumber + "' style='visibility:hidden;' />";
569
570                         s += "<input type='checkbox' class='export' id='export_" + oObj.biblionumber + "' name='biblionumbers' value='" + oObj.biblionumber + "' />";
571                         return s;
572                     }
573                 }
574             ],
575             "fnFooterCallback": function ( nRow, aaData, iStart, iEnd, aiDisplay ) {
576                 var total_charge = 0;
577                 var total_fine  = 0;
578                 var total_price = 0;
579                 for ( var i=0; i < aaData.length; i++ ) {
580                     total_charge += aaData[i]['charge'] * 1;
581                     total_fine += aaData[i]['fine'] * 1;
582                     total_price  += aaData[i]['price'] * 1;
583                 }
584                 $("#totaldue").html(total_charge.toFixed(2));
585                 $("#totalfine").html(total_fine.toFixed(2));
586                 $("#totalprice").html(total_price.toFixed(2));
587             },
588             "bPaginate": false,
589             "bProcessing": true,
590             "bServerSide": false,
591             "sAjaxSource": '/cgi-bin/koha/svc/checkouts',
592             "fnServerData": function ( sSource, aoData, fnCallback ) {
593                 aoData.push( { "name": "borrowernumber", "value": borrowernumber } );
594
595                 $.getJSON( sSource, aoData, function (json) {
596                     fnCallback(json)
597                 } );
598             },
599             "rowGroup":{
600                 "dataSrc": "issued_today",
601                 "startRender": function ( rows, group ) {
602                     if ( group ) {
603                         return TODAYS_CHECKOUTS;
604                     } else {
605                         return PREVIOUS_CHECKOUTS;
606                     }
607                 }
608             },
609             "fnInitComplete": function(oSettings, json) {
610                 // Build a summary of checkouts grouped by itemtype
611                 var checkoutsByItype = json.aaData.reduce(function (obj, row) {
612                     obj[row.type_for_stat] = (obj[row.type_for_stat] || 0) + 1;
613                     return obj;
614                 }, {});
615                 var ul = $('<ul>');
616                 Object.keys(checkoutsByItype).sort().forEach(function (itype) {
617                     var li = $('<li>')
618                         .append($('<strong>').html(itype || MSG_NO_ITEMTYPE))
619                         .append(': ' + checkoutsByItype[itype]);
620                     ul.append(li);
621                 })
622                 $('<details>')
623                     .addClass('checkouts-by-itemtype')
624                     .append($('<summary>').html(MSG_CHECKOUTS_BY_ITEMTYPE))
625                     .append(ul)
626                     .insertBefore(oSettings.nTableWrapper)
627             },
628         }, columns_settings_issues_table);
629
630         if ( $("#issues-table").length ) {
631             $("#issues-table_processing").position({
632                 of: $( "#issues-table" ),
633                 collision: "none"
634             });
635         }
636     }
637
638     // Don't load relatives' issues table unless it is clicked on
639     var relativesIssuesTable;
640     $("#relatives-issues-tab").click( function() {
641         if ( ! relativesIssuesTable ) {
642             relativesIssuesTable = $("#relatives-issues-table").dataTable($.extend(true, {}, dataTablesDefaults, {
643                 "bAutoWidth": false,
644                 "sDom": "rt",
645                 "aaSorting": [],
646                 "aoColumns": [
647                     {
648                         "mDataProp": "date_due",
649                         "bVisible": false,
650                     },
651                     {
652                         "iDataSort": 0, // Sort on hidden unformatted date due column
653                         "mDataProp": function( oObj ) {
654                             var today = new Date();
655                             var due = new Date( oObj.date_due );
656                             if ( today > due ) {
657                                 return "<span class='overdue'>" + oObj.date_due_formatted + "</span>";
658                             } else {
659                                 return oObj.date_due_formatted;
660                             }
661                         }
662                     },
663                     {
664                         "mDataProp": function ( oObj ) {
665                             title = "<span class='strong'><a href='/cgi-bin/koha/catalogue/detail.pl?biblionumber="
666                                   + oObj.biblionumber
667                                   + "'>"
668                                   + oObj.title.escapeHtml();
669
670                             $.each(oObj.subtitle, function( index, value ) {
671                                       title += " " + value.escapeHtml();
672                             });
673
674                             title += " " + oObj.part_number + " " + oObj.part_name;
675
676                             if ( oObj.enumchron ) {
677                                 title += " (" + oObj.enumchron.escapeHtml() + ")";
678                             }
679
680                             title += "</a></span>";
681
682                             if ( oObj.author ) {
683                                 title += " " + BY.replace( "_AUTHOR_", " " + oObj.author.escapeHtml() );
684                             }
685
686                             if ( oObj.itemnotes ) {
687                                 var span_class = "";
688                                 if ( $.datepicker.formatDate('yy-mm-dd', new Date(oObj.issuedate) ) == ymd ) {
689                                     span_class = "circ-hlt";
690                                 }
691                                 title += " - <span class='" + span_class + "'>" + oObj.itemnotes.escapeHtml() + "</span>"
692                             }
693
694                             if ( oObj.itemnotes_nonpublic ) {
695                                 var span_class = "";
696                                 if ( $.datepicker.formatDate('yy-mm-dd', new Date(oObj.issuedate) ) == ymd ) {
697                                     span_class = "circ-hlt";
698                                 }
699                                 title += " - <span class='" + span_class + "'>" + oObj.itemnotes_nonpublic.escapeHtml() + "</span>"
700                             }
701
702                             var onsite_checkout = '';
703                             if ( oObj.onsite_checkout == 1 ) {
704                                 onsite_checkout += " <span class='onsite_checkout'>(" + INHOUSE_USE + ")</span>";
705                             }
706
707                             title += " "
708                                   + "<a href='/cgi-bin/koha/catalogue/moredetail.pl?biblionumber="
709                                   + oObj.biblionumber
710                                   + "&itemnumber="
711                                   + oObj.itemnumber
712                                   + "#"
713                                   + oObj.itemnumber
714                                   + "'>"
715                                   + (oObj.barcode ? oObj.barcode.escapeHtml() : "")
716                                   + "</a>"
717                                   + onsite_checkout;
718
719                             return title;
720                         },
721                         "sType": "anti-the"
722                     },
723                     {
724                         "mDataProp": function ( oObj ) {
725                             return oObj.recordtype_description.escapeHtml();
726                         }
727                     },
728                     {
729                         "mDataProp": function ( oObj ) {
730                             return oObj.itemtype_description.escapeHtml();
731                         }
732                     },
733                     {
734                         "mDataProp": function ( oObj ) {
735                             return ( oObj.collection ? oObj.collection.escapeHtml() : '' );
736                         }
737                     },
738                     {
739                         "mDataProp": function ( oObj ) {
740                             return ( oObj.location ? oObj.location.escapeHtml() : '' );
741                         }
742                     },
743                     {
744                         "mDataProp": "issuedate",
745                         "bVisible": false,
746                     },
747                     {
748                         "iDataSort": 7, // Sort on hidden unformatted issuedate column
749                         "mDataProp": "issuedate_formatted",
750                     },
751                     {
752                         "mDataProp": function ( oObj ) {
753                             return oObj.branchname.escapeHtml();
754                         }
755                     },
756                     {
757                         "mDataProp": function ( oObj ) {
758                             return ( oObj.itemcallnumber ? oObj.itemcallnumber.escapeHtml() : '' );
759                         }
760                     },
761                     {
762                         "mDataProp": function ( oObj ) {
763                             if ( ! oObj.charge ) oObj.charge = 0;
764                             return parseFloat(oObj.charge).toFixed(2);
765                         }
766                     },
767                     {
768                         "mDataProp": function ( oObj ) {
769                             if ( ! oObj.fine ) oObj.fine = 0;
770                             return parseFloat(oObj.fine).toFixed(2);
771                         }
772                     },
773                     {
774                         "mDataProp": function ( oObj ) {
775                             if ( ! oObj.price ) oObj.price = 0;
776                             return parseFloat(oObj.price).toFixed(2);
777                         }
778                     },
779                     {
780                         "mDataProp": function( oObj ) {
781                             return "<a href='/cgi-bin/koha/members/moremember.pl?borrowernumber=" + oObj.borrowernumber + "'>"
782                                 + oObj.borrower.firstname.escapeHtml()
783                                 + " " +
784                                 oObj.borrower.surname.escapeHtml()
785                                 + " (" + oObj.borrower.cardnumber.escapeHtml() + ")</a>"
786                         }
787                     },
788                 ],
789                 "bPaginate": false,
790                 "bProcessing": true,
791                 "bServerSide": false,
792                 "sAjaxSource": '/cgi-bin/koha/svc/checkouts',
793                 "fnServerData": function ( sSource, aoData, fnCallback ) {
794                     $.each(relatives_borrowernumbers, function( index, value ) {
795                         aoData.push( { "name": "borrowernumber", "value": value } );
796                     });
797
798                     $.getJSON( sSource, aoData, function (json) {
799                         fnCallback(json)
800                     } );
801                 },
802             }));
803         }
804     });
805
806     if ( $("#relatives-issues-table").length ) {
807         $("#relatives-issues-table_processing").position({
808             of: $( "#relatives-issues-table" ),
809             collision: "none"
810         });
811     }
812
813     if ( AllowRenewalLimitOverride || AllowRenewalOnHoldOverride ) {
814         $( '#override_limit' ).click( function () {
815             if ( this.checked ) {
816                 if ( AllowRenewalLimitOverride ) {
817                     $( '.renewals-allowed' ).show();
818                     $( '.renewals-disabled' ).hide();
819                 }
820                 if ( AllowRenewalOnHoldOverride ) {
821                     $( '.renewals-allowed-on_reserve' ).show();
822                 }
823             } else {
824                 $( '.renewals-allowed' ).hide();
825                 $( '.renewals-allowed-on_reserve' ).hide();
826                 $( '.renewals-disabled' ).show();
827             }
828         } ).prop('checked', false);
829     }
830
831     // Handle return claims
832     $(document).on("click", '.claim-returned-btn', function(e){
833         e.preventDefault();
834         itemnumber = $(this).data('itemnumber');
835
836         $('#claims-returned-itemnumber').val(itemnumber);
837         $('#claims-returned-notes').val("");
838         $('#claims-returned-charge-lost-fee').attr('checked', false)
839         $('#claims-returned-modal').modal()
840     });
841     $(document).on("click", '#claims-returned-modal-btn-submit', function(e){
842         let itemnumber = $('#claims-returned-itemnumber').val();
843         let notes = $('#claims-returned-notes').val();
844         let fee = $('#claims-returned-charge-lost-fee').attr('checked') ? true : false;
845
846         $('#claims-returned-modal').modal('hide')
847
848         $('.claim-returned-btn[data-itemnumber="' + itemnumber + '"]').replaceWith('<img id="return_claim_spinner_' + itemnumber + ' src=' + interface + '/' + theme + '/img/spinner-small.gif />');
849
850         params = {
851             item_id: itemnumber,
852             notes: notes,
853             charge_lost_fee: fee,
854             created_by: logged_in_user_borrowernumber,
855         };
856
857         $.post( '/api/v1/return_claims', JSON.stringify(params), function( data ) {
858
859             id = "#return_claim_spinner_" + data.item_id;
860
861             let created_on = new Date(data.created_on);
862
863             let content = "";
864             if ( data.claim_id ) {
865                 content = '<span class="badge">' + created_on.toLocaleDateString() + '</span>';
866                 $(id).parent().parent().addClass('ok');
867             } else {
868                 content = RETURN_CLAIMED_FAILURE;
869                 $(id).parent().parent().addClass('warn');
870             }
871
872             $(id).replaceWith( content );
873
874             refreshReturnClaimsTable();
875         }, "json")
876
877     });
878
879
880     // Don't load return claims table unless it is clicked on
881     var returnClaimsTable;
882     $("#return-claims-tab").click( function() {
883         refreshReturnClaimsTable();
884     });
885
886     function refreshReturnClaimsTable(){
887         loadReturnClaimsTable();
888         $("#return-claims-table").DataTable().ajax.reload();
889     }
890     function loadReturnClaimsTable() {
891         if ( ! returnClaimsTable ) {
892             returnClaimsTable = $("#return-claims-table").dataTable({
893                 "bAutoWidth": false,
894                 "sDom": "rt",
895                 "aaSorting": [],
896                 "aoColumns": [
897                     {
898                         "mDataProp": "id",
899                         "bVisible": false,
900                     },
901                     {
902                         "mDataProp": function ( oObj ) {
903                               let title = '<a class="return-claim-title strong" href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=' + oObj.biblionumber + '">'
904                                   + oObj.title
905                                   + ( oObj.enumchron || "" )
906                               + '</a>';
907                               if ( oObj.author ) {
908                                 title += ' by ' + oObj.author;
909                               }
910                               title += ' <a href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=' + oObj.biblionumber + '&itemnumber=' + oObj.itemnumber + '">' + oObj.barcode + '</a>';
911
912                               return title;
913                         }
914                     },
915                     {
916                         "sClass": "return-claim-notes-td",
917                         "mDataProp": function ( oObj ) {
918                             return '<span id="return-claim-notes-static-' + oObj.id + '" class="return-claim-notes" data-return-claim-id="' + oObj.id + '">' + oObj.notes + '</span>'
919                                 + '<i style="float:right" class="fa fa-pencil-square-o" title="Double click to edit"></i>';
920                         }
921                     },
922                     {
923                         "mDataProp": function ( oObj ) {
924                             let created_on = new Date( oObj.created_on );
925                             return created_on.toLocaleDateString();
926                         }
927                     },
928                     {
929                         "mDataProp": function ( oObj ) {
930                             let updated_on = new Date( oObj.updated_on );
931                             return updated_on.toLocaleDateString();
932                         }
933                     },
934                     {
935                         "mDataProp": function ( oObj ) {
936                             if ( ! oObj.resolution ) return "";
937
938                             let desc = '<strong>' + oObj.resolution_data.lib + '</strong> on <i>' + oObj.resolved_on + '</i>';
939                             if (oObj.resolved_by_data) desc += ' by <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>';
940                             return desc;
941                         }
942                     },
943                     {
944                         "mDataProp": function ( oObj ) {
945                             let delete_html = oObj.resolved_on
946                                 ? '<li><a href="#" class="return-claim-tools-delete" data-return-claim-id="' + oObj.id + '"><i class="fa fa-trash"></i> Delete</a></li>'
947                                 : "";
948                             let resolve_html = ! oObj.resolution
949                                 ? '<li><a href="#" class="return-claim-tools-resolve" data-return-claim-id="' + oObj.id + '"><i class="fa fa-check-square"></i> Resolve</a></li>'
950                                 : "";
951
952                             return  '<div class="btn-group">'
953                                   + ' <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">'
954                                   + '  Actions <span class="caret"></span>'
955                                   + ' </button>'
956                                   + ' <ul class="dropdown-menu">'
957                                   + '  <li><a href="#" class="return-claim-tools-editnotes" data-return-claim-id="' + oObj.id + '"><i class="fa fa-edit"></i> Edit notes</a></li>'
958                                   + resolve_html
959                                   + delete_html
960                                   + ' </ul>'
961                                   + ' </div>';
962                         }
963                     },
964                 ],
965                 "bPaginate": false,
966                 "bProcessing": true,
967                 "bServerSide": false,
968                 "sAjaxSource": '/cgi-bin/koha/svc/return_claims',
969                 "fnServerData": function ( sSource, aoData, fnCallback ) {
970                     aoData.push( { "name": "borrowernumber", "value": borrowernumber } );
971
972                     $.getJSON( sSource, aoData, function (json) {
973                         let resolved = json.resolved;
974                         let unresolved = json.unresolved;
975
976                         $('#return-claims-count-resolved').text(resolved);
977                         $('#return-claims-count-unresolved').text(unresolved);
978
979                         fnCallback(json)
980                     } );
981                 },
982             });
983         }
984     }
985
986     $('body').on('click', '.return-claim-tools-editnotes', function() {
987         let id = $(this).data('return-claim-id');
988         $('#return-claim-notes-static-' + id).parent().dblclick();
989     });
990     $('body').on('dblclick', '.return-claim-notes-td', function() {
991         let elt = $(this).children('.return-claim-notes');
992         let id = elt.data('return-claim-id');
993         if ( $('#return-claim-notes-editor-textarea-' + id).length == 0 ) {
994             let note = elt.text();
995             let editor =
996                 '  <span id="return-claim-notes-editor-' + id + '">'
997                 + ' <textarea id="return-claim-notes-editor-textarea-' + id + '">' + note + '</textarea>'
998                 + ' <br/>'
999                 + ' <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>'
1000                 + ' <a class="claim-returned-notes-editor-cancel" data-return-claim-id="' + id + '" href="#">Cancel</a>'
1001                 + '</span>';
1002             elt.hide();
1003             $(editor).insertAfter( elt );
1004         }
1005     });
1006
1007     $('body').on('click', '.claim-returned-notes-editor-submit', function(){
1008         let id = $(this).data('return-claim-id');
1009         let notes = $('#return-claim-notes-editor-textarea-' + id).val();
1010
1011         let params = {
1012             notes: notes,
1013             updated_by: logged_in_user_borrowernumber
1014         };
1015
1016         $(this).parent().remove();
1017
1018         $.ajax({
1019             url: '/api/v1/return_claims/' + id + '/notes',
1020             type: 'PUT',
1021             data: JSON.stringify(params),
1022             success: function( data ) {
1023                 let notes = $('#return-claim-notes-static-' + id);
1024                 notes.text(data.notes);
1025                 notes.show();
1026             },
1027             contentType: "json"
1028         });
1029     });
1030
1031     $('body').on('click', '.claim-returned-notes-editor-cancel', function(){
1032         let id = $(this).data('return-claim-id');
1033         $(this).parent().remove();
1034         $('#return-claim-notes-static-' + id).show();
1035     });
1036
1037     // Hanld return claim deletion
1038     $('body').on('click', '.return-claim-tools-delete', function() {
1039         let confirmed = confirm(CONFIRM_DELETE_RETURN_CLAIM);
1040         if ( confirmed ) {
1041             let id = $(this).data('return-claim-id');
1042
1043             $.ajax({
1044                 url: '/api/v1/return_claims/' + id,
1045                 type: 'DELETE',
1046                 success: function( data ) {
1047                     refreshReturnClaimsTable();
1048                 }
1049             });
1050         }
1051     });
1052
1053     // Handle return claim resolution
1054     $('body').on('click', '.return-claim-tools-resolve', function() {
1055         let id = $(this).data('return-claim-id');
1056
1057         $('#claims-returned-resolved-modal-id').val(id);
1058         $('#claims-returned-resolved-modal').modal()
1059     });
1060
1061     $(document).on('click', '#claims-returned-resolved-modal-btn-submit', function(e) {
1062         let resolution = $('#claims-returned-resolved-modal-resolved-code').val();
1063         let id = $('#claims-returned-resolved-modal-id').val();
1064
1065         $('#claims-returned-resolved-modal-btn-submit-spinner').show();
1066         $('#claims-returned-resolved-modal-btn-submit-icon').hide();
1067
1068         params = {
1069           resolution: resolution,
1070           updated_by: logged_in_user_borrowernumber
1071         };
1072
1073         $.ajax({
1074             url: '/api/v1/return_claims/' + id + '/resolve',
1075             type: 'PUT',
1076             data: JSON.stringify(params),
1077             success: function( data ) {
1078                 $('#claims-returned-resolved-modal-btn-submit-spinner').hide();
1079                 $('#claims-returned-resolved-modal-btn-submit-icon').show();
1080                 $('#claims-returned-resolved-modal').modal('hide')
1081
1082                 refreshReturnClaimsTable();
1083             },
1084             contentType: "json"
1085         });
1086
1087     });
1088
1089  });