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