Bug 9302: Add ability to merge patron records
[koha.git] / koha-tmpl / intranet-tmpl / prog / en / modules / members / member.tt
1 [% USE Asset %]
2 [% USE Koha %]
3 [% USE ColumnsSettings %]
4 [% USE Branches %]
5 [% USE Categories %]
6 [% SET footerjs = 1 %]
7 [% INCLUDE 'doc-head-open.inc' %]
8 <title>Koha &rsaquo; Patrons [% IF ( searching ) %]&rsaquo; Search results[% END %]</title>
9 [% INCLUDE 'doc-head-close.inc' %]
10 [% Asset.css("css/datatables.css") %]
11 </head>
12
13 <body id="pat_member" class="pat">
14 [% INCLUDE 'header.inc' %]
15 [% INCLUDE 'patron-search.inc' %]
16
17 <div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; [% IF ( searching ) %]<a href="/cgi-bin/koha/members/members-home.pl">Patrons</a>  &rsaquo; Search results[% ELSE %]Patrons[% END %]</div>
18
19 <div id="doc3" class="yui-t2">
20   <div id="bd">
21     <div id="yui-main">
22       <div class="yui-b">
23         <div class="yui-g">
24           [% IF CAN_user_tools_manage_patron_lists %]
25             <div id="patron_list_dialog" class="dialog alert">
26               Added <span class="patrons-length"></span> patrons to <a></a>.
27             </div>
28           [% END %]
29
30           [% IF Koha.Preference( 'NorwegianPatronDBEnable' ) == 1 %]
31             [% SET nl_search_form_title='Search the Norwegian national patron database' %]
32             [% INCLUDE 'nl-search-form.tt' %]
33           [% END %]
34
35           [% INCLUDE 'patron-toolbar.inc' %]
36           [% INCLUDE 'noadd-warnings.inc' %]
37
38           <div class="browse">
39             Browse by last name:
40             [% FOREACH letter IN alphabet.split(' ') %]
41                 <a href="#" class="filterByLetter">[% letter %]</a>
42             [% END %]
43           </div>
44
45           [% IF CAN_user_borrowers_edit_borrowers && pending_borrower_modifications %]
46             <div class="pending-info" id="patron_updates_pending">
47               <a href="/cgi-bin/koha/members/members-update.pl">Patrons requesting modifications</a>:
48               <span class="number_box"><a href="/cgi-bin/koha/members/members-update.pl">[% pending_borrower_modifications %]</a></span>
49             </div>
50           [% END %]
51
52           <div id="searchresults">
53             <div id="searchheader">
54               <h3>Patrons found for: <span id="searchpattern">[% IF searchmember %] for '[% searchmember | html %]'[% END %]</span></h3>
55             </div>
56             [% IF CAN_user_tools_manage_patron_lists || CAN_user_borrowers %]
57               <div id="searchheader">
58                   <div>
59                     [% IF CAN_user_tools_manage_patron_lists %]
60                       <a href="#" id="select_all"><i class="fa fa-check"></i> Select all</a>
61                       |
62                       <a href="#" id="clear_all"><i class="fa fa-remove"></i> Clear all</a>
63                       |
64                       <span>
65                           <label for="add_to_patron_list">Add selected patrons to:</label>
66                           <select id="add_to_patron_list" name="add_to_patron_list">
67                               <option value=""></option>
68                               [% IF patron_lists %]
69                                   <optgroup label="Patron lists:">
70                                       [% FOREACH pl IN patron_lists %]
71                                           <option value="[% pl.patron_list_id %]">[% pl.name |html %]</option>
72                                       [% END %]
73                                   </optgroup>
74                               [% END %]
75
76                               <option value="new">[ New list ]</option>
77                           </select>
78
79                           <input type="text" id="new_patron_list" name="new_patron_list" id="new_patron_list" />
80
81                           <input id="add_to_patron_list_submit" type="submit" class="submit" value="Save">
82                       </span>
83                     [% END %]
84
85                     [% IF CAN_user_tools_manage_patron_lists && CAN_user_borrowers %]
86                         |
87                     [% END %]
88
89                     [% IF CAN_user_borrowers %]
90                           <button id="merge-patrons" type="submit">Merge selected patrons</button>
91                     [% END %]
92                   </div>
93                 </div>
94             [% END %]
95
96             <table id="memberresultst">
97               <thead>
98                 <tr>
99                 [% IF CAN_user_tools_manage_patron_lists %]
100                   <th>&nbsp;</th>
101                 [% END %]
102                   <th>Card</th>
103                   <th>Name</th>
104                   <th>Date of birth</th>
105                   <th>Category</th>
106                   <th>Library</th>
107                   <th>Expires on</th>
108                   <th>OD/Checkouts</th>
109                   <th>Fines</th>
110                   <th>Circ note</th>
111                   <th>&nbsp;</th>
112                 </tr>
113               </thead>
114               <tbody></tbody>
115             </table>
116           </div>
117         </div>
118       </div>
119     </div>
120     <div class="yui-b">
121       <form method="get" id="searchform">
122         <input type="hidden" id="firstletter_filter" value="" />
123         <fieldset class="brief">
124           <h3>Filters</h3>
125           <ol>
126             <li>
127               <label for="searchmember_filter">Search:</label>
128               <input type="text" id="searchmember_filter" value="[% searchmember %]"/>
129             </li>
130             <li>
131               <label for="searchfieldstype_filter">Search fields:</label>
132               <select name="searchfieldstype" id="searchfieldstype_filter">
133                 [% IF searchfieldstype == "standard" %]
134                   <option selected="selected" value='standard'>Standard</option>
135                 [% ELSE %]
136                   <option value='standard'>Standard</option>
137                 [% END %]
138                 [% IF searchfieldstype == "surname" %]
139                   <option selected="selected" value='surname'>Surname</option>
140                 [% ELSE %]
141                   <option value='surname'>Surname</option>
142                 [% END %]
143                 [% IF searchfieldstype == "email" %]
144                   <option selected="selected" value='email'>Email</option>
145                 [% ELSE %]
146                   <option value='email'>Email</option>
147                 [% END %]
148                 [% IF searchfieldstype == "borrowernumber" %]
149                   <option selected="selected" value='borrowernumber'>Borrower number</option>
150                 [% ELSE %]
151                   <option value='borrowernumber'>Borrower number</option>
152                 [% END %]
153                 [% IF searchfieldstype == "userid" %]
154                   <option selected="selected" value='userid'>Username</option>
155                 [% ELSE %]
156                   <option value='userid'>Username</option>
157                 [% END %]
158                 [% IF searchfieldstype == "phone" %]
159                   <option selected="selected" value='phone'>Phone number</option>
160                 [% ELSE %]
161                   <option value='phone'>Phone number</option>
162                 [% END %]
163                 [% IF searchfieldstype == "address" %]
164                   <option selected="selected" value='address'>Street address</option>
165                 [% ELSE %]
166                   <option value='address'>Street address</option>
167                 [% END %]
168                 [% IF searchfieldstype == "dateofbirth" %]
169                   <option selected="selected" value='dateofbirth'>Date of birth</option>
170                 [% ELSE %]
171                   <option value='dateofbirth'>Date of birth</option>
172                 [% END %]
173                 [% IF searchfieldstype == "sort1" %]
174                   <option selected="selected" value='sort1'>Sort field 1</option>
175                 [% ELSE %]
176                   <option value='sort1'>Sort field 1</option>
177                 [% END %]
178                 [% IF searchfieldstype == "sort2" %]
179                   <option selected="selected" value='sort2'>Sort field 2</option>
180                 [% ELSE %]
181                   <option value='sort2'>Sort field 2</option>
182                 [% END %]
183               </select>
184             </li>
185             <li>
186               <label for="searchtype_filter">Search type:</label>
187               <select name="searchtype" id="searchtype_filter">
188                 [% IF searchtype == "start_with" %]
189                   <option value='start_with' selected="selected">Starts with</option>
190                   <option value="contain">Contains</option>
191                 [% ELSE %]
192                   <option value='start_with'>Starts with</option>
193                   <option value="contain" selected="selected">Contains</option>
194                 [% END %]
195               </select>
196             </li>
197             <li>
198               <label for="categorycode_filter">Category:</label>
199               [% SET categories = Categories.all() %]
200               <select id="categorycode_filter">
201                 <option value="">Any</option>
202                 [% FOREACH cat IN categories %]
203                   [% IF cat.categorycode == categorycode_filter %]
204                     <option selected="selected" value="[% cat.categorycode %]">[% cat.description |html %]</option>
205                   [% ELSE %]
206                     <option value="[% cat.categorycode %]">[% cat.description |html %]</option>
207                   [% END %]
208                 [% END %]
209               </select>
210             </li>
211             <li>
212               <label for="branchcode_filter">Library:</label>
213               [% SET branches = Branches.all( selected => branchcode_filter, only_from_group => 1 ) %]
214               <select id="branchcode_filter">
215                 [% IF branches.size != 1 %]
216                   <option value="">Any</option>
217                 [% END %]
218                 [% PROCESS options_for_libraries libraries => branches %]
219               </select>
220             </li>
221           </ol>
222           <fieldset class="action">
223             <input type="submit" value="Search" />
224             <input type="button" value="Clear" id="clear_search" />
225           </fieldset>
226         </fieldset>
227       </form>
228     </div>
229   </div>
230   <div class="yui-g">
231     [% INCLUDE 'members-menu.inc' %]
232   </div>
233 </div>
234
235 [% MACRO jsinclude BLOCK %]
236     [% INCLUDE 'datatables.inc' %]
237     [% INCLUDE 'columns_settings.inc' %]
238     [% Asset.js("js/members-menu.js") %]
239     <script type="text/javascript">
240         $(document).ready(function() {
241             $('#merge-patrons').prop('disabled', true);
242             $('#memberresultst').on('change', 'input.selection', function() {
243                 if ( $('.selection:checked').length > 1 ) {
244                     $('#merge-patrons').prop('disabled', false);
245                 } else {
246                     $('#merge-patrons').prop('disabled', true);
247                 }
248             });
249             $('#merge-patrons').on('click', function() {
250                 var merge_patrons_url = 'merge-patrons.pl?' + $('.selection:checked')
251                     .map(function() {
252                        return "id=" + $(this).val()
253                     }).get().join('&');
254
255                 window.location.href = merge_patrons_url;
256             });
257
258             $('#add_to_patron_list_submit').prop('disabled', true);
259             $('#new_patron_list').hide();
260
261             $('#add_to_patron_list').change(function() {
262                 var value = $('#add_to_patron_list').val();
263                 if ( value == 'new' ) {
264                     $('#new_patron_list').val('')
265                     $('#new_patron_list').show();
266                     $('#new_patron_list').focus();
267                 } else if ( value ) {
268                     $('#new_patron_list').hide();
269                     $('#add_to_patron_list_submit').prop('disabled', false);
270                 } else {
271                     $('#new_patron_list').hide();
272                     $('#add_to_patron_list_submit').prop('disabled', true);
273                 }
274             });
275
276             $('#new_patron_list').on('input', function() {
277                 if ( $('#new_patron_list').val() ) {
278                     $('#add_to_patron_list_submit').prop('disabled', false);
279                 } else {
280                     $('#add_to_patron_list_submit').prop('disabled', true);
281                 }
282             });
283
284             $("#add_to_patron_list_submit").on('click', function(e){
285                 if ( $('#add_to_patron_list').val() == 'new' ) {
286                     if ( $('#new_patron_list').val() ) {
287                         $("#add_to_patron_list option").each(function() {
288                             if ( $(this).text() == $('#new_patron_list').val() ) {
289                                 alert( _("You already have a list with that name!") );
290                                 return false;
291                             }
292                         });
293                     } else {
294                         alert( _("You must give your new patron list a name!") );
295                         return false;
296                     }
297                 }
298
299                 if ( $("#memberresultst input:checkbox:checked").length == 0 ) {
300                     alert( _("You have not selected any patrons to add to a list!") );
301                     return false;
302                 }
303
304                 var borrowernumbers = [];
305                 $("#memberresultst").find("input:checkbox:checked").each(function(){
306                     borrowernumbers.push($(this).val());
307                 });
308                 var data = {
309                     add_to_patron_list: $("#add_to_patron_list").val(),
310                     new_patron_list: $("#new_patron_list").val(),
311                     borrowernumbers: borrowernumbers
312                 };
313                 $.ajax({
314                     data: data,
315                     type: 'POST',
316                     url: '/cgi-bin/koha/svc/members/add_to_list',
317                     success: function(data) {
318                         $("#patron_list_dialog").show();
319                         $("#patron_list_dialog > span.patrons-length").html(data.patrons_added_to_list);
320                         $("#patron_list_dialog > a").attr("href", "/cgi-bin/koha/patron_lists/list.pl?patron_list_id=" + data.patron_list.patron_list_id);
321                         $("#patron_list_dialog > a").html(data.patron_list.name);
322                         if ( $('#add_to_patron_list').val() == 'new' ) {
323                             var new_patron_list_added = $("<option>", {
324                                 value: data.patron_list.patron_list_id,
325                                 text: data.patron_list.name
326                             });
327                             $("#add_to_patron_list optgroup").append(new_patron_list_added);
328                             $("#add_to_patron_list").val(data.patron_list.patron_list_id);
329                             $("#new_patron_list").val('');
330                             $('#add_to_patron_list').change();
331                         }
332                     },
333                     error: function() {
334                         alert("an error occurred");
335                     }
336                 });
337                 return true;
338             });
339             $(".filterByLetter").on("click",function(e){
340                 e.preventDefault();
341                 filterByFirstLetterSurname($(this).text());
342             });
343             $("#select_all").on("click",function(e){
344                 e.preventDefault();
345                 $(".selection").prop("checked", true);
346             });
347             $("#clear_all").on("click",function(e){
348                 e.preventDefault();
349                 $(".selection").prop("checked", false);
350             });
351             $("#clear_search").on("click",function(e){
352                 e.preventDefault();
353                 clearFilters(true);
354             });
355             $("#searchform").on("submit", filter);
356         });
357
358         var dtMemberResults;
359         var search = 1;
360         $(document).ready(function() {
361             [% IF searchmember %]
362                 $("#searchmember_filter").val("[% searchmember | html %]");
363             [% END %]
364             [% IF searchfieldstype %]
365                 $("searchfieldstype_filter").val("[% searchfieldstype %]");
366             [% END %]
367             [% IF searchtype %]
368                 $("#searchtype_filter").val("[% searchtype %]");
369             [% END %]
370             [% IF categorycode %]
371                 $("#categorycode_filter").val("[% categorycode_filter %]");
372             [% END %]
373             [% IF branchcode %]
374                 $("#branchcode_filter").val("[% branchcode_filter %]");
375             [% END %]
376
377             [% IF view != "show_results" %]
378                 search = 0;
379             [% ELSE %]
380                 $("#searchresults").show();
381             [% END %]
382
383             // Build the aLengthMenu
384             var aLengthMenu = [
385                 [%PatronsPerPage %], 10, 20, 50, 100, -1
386             ];
387             jQuery.unique(aLengthMenu);
388             aLengthMenu.sort(function( a, b ){
389                 // Put "All" at the end
390                 if ( a == -1 ) {
391                     return 1;
392                 } else if ( b == -1 ) {
393                     return -1;
394                 }
395                 return parseInt(a) < parseInt(b) ? -1 : 1;}
396             );
397             var aLengthMenuLabel = [];
398             $(aLengthMenu).each(function(){
399                 if ( this == -1 ) {
400                     // Label for -1 is "All"
401                     aLengthMenuLabel.push(_("All"));
402                 } else {
403                     aLengthMenuLabel.push(this);
404                 }
405             });
406
407             // Apply DataTables on the results table
408             var columns_settings = [% ColumnsSettings.GetColumns( 'members', 'member', 'memberresultst', 'json' ) %];
409             [% UNLESS CAN_user_tools_manage_patron_lists %]
410                 [%# Remove the first column if we do not display the checkbox %]
411                 columns_settings.splice(0, 1);
412             [% END %]
413             dtMemberResults = KohaTable("memberresultst", {
414                 'bServerSide': true,
415                 'sAjaxSource': "/cgi-bin/koha/svc/members/search",
416                 'fnServerData': function(sSource, aoData, fnCallback) {
417                     if ( ! search ) {
418                         return;
419                     }
420                     aoData.push({
421                         'name': 'searchmember',
422                         'value': $("#searchmember_filter").val()
423                     },{
424                         'name': 'firstletter',
425                         'value': $("#firstletter_filter").val()
426                     },{
427                         'name': 'searchfieldstype',
428                         'value': $("#searchfieldstype_filter").val()
429                     },{
430                         'name': 'searchtype',
431                         'value': $("#searchtype_filter").val()
432                     },{
433                         'name': 'categorycode',
434                         'value': $("#categorycode_filter").val()
435                     },{
436                         'name': 'branchcode',
437                         'value': $("#branchcode_filter").val()
438                     },{
439                         'name': 'name_sorton',
440                         'value': 'borrowers.surname borrowers.firstname'
441                     },{
442                         'name': 'dateofbirth',
443                         'value': 'borrowers.dateofbirth',
444                     },{
445                         'name': 'category_sorton',
446                         'value': 'categories.description',
447                     },{
448                         'name': 'branch_sorton',
449                         'value': 'branches.branchname'
450                     },{
451                         'name': 'template_path',
452                         'value': 'members/tables/members_results.tt',
453                     });
454                     $.ajax({
455                         'dataType': 'json',
456                         'type': 'POST',
457                         'url': sSource,
458                         'data': aoData,
459                         'success': function(json){
460                             // redirect if there is only 1 result.
461                             if ( json.aaData.length == 1 ) {
462                                 var borrowernumber = json.aaData[0].borrowernumber;
463                                 document.location.href="/cgi-bin/koha/members/moremember.pl?borrowernumber="+borrowernumber;
464                                 return false;
465                             }
466                             fnCallback(json);
467                         }
468                     });
469                 },
470                 'aoColumns':[
471                     [% IF CAN_user_tools_manage_patron_lists %]
472                       { 'mDataProp': 'dt_borrowernumber', 'bSortable': false },
473                     [% END %]
474                     { 'mDataProp': 'dt_cardnumber' },
475                     { 'mDataProp': 'dt_name' },
476                     { 'mDataProp': 'dt_dateofbirth' },
477                     { 'mDataProp': 'dt_category' },
478                     { 'mDataProp': 'dt_branch' },
479                     { 'mDataProp': 'dt_dateexpiry' },
480                     { 'mDataProp': 'dt_od_checkouts', 'bSortable': false },
481                     { 'mDataProp': 'dt_fines', 'bSortable': false },
482                     { 'mDataProp': 'dt_borrowernotes' },
483                     { 'mDataProp': 'dt_action', 'bSortable': false, 'sClass': 'actions' }
484                 ],
485                 'fnRowCallback': function(nRow, aData, iDisplayIndex, iDisplayIndexFull) {
486                     /* Center text for 6th column */
487                     $("td:eq(5)", nRow).css("text-align", "center");
488
489                     return nRow;
490                 },
491                 'bFilter': false,
492                 'bAutoWidth': false,
493                 [% IF CAN_user_tools_manage_patron_lists %]
494                     'aaSorting': [[2, 'asc']],
495                 [% ELSE %]
496                     'aaSorting': [[1, 'asc']],
497                 [% END %]
498                 "aLengthMenu": [aLengthMenu, aLengthMenuLabel],
499                 'sPaginationType': 'full_numbers',
500                 "iDisplayLength": [% PatronsPerPage %],
501                 "bProcessing": true,
502             }, columns_settings);
503             update_searched();
504         });
505
506         // Update the string "Results found ..."
507         function update_searched(){
508             var searched = $("#searchfieldstype_filter").find("option:selected").text();
509             if ( $("#searchmember_filter").val() ) {
510                 if ( $("#searchtype_filter").val() == 'start_with' ) {
511                     searched += _(" starting with ");
512                 } else {
513                     searched += _(" containing ");
514                 }
515                 searched += "'" + $("#searchmember_filter").val() + "'";
516             }
517             if ( $("#firstletter_filter").val() ) {
518                 searched += _(" begins with ") + "'" + $("#firstletter_filter").val() +"'";
519             }
520             if ( $("#categorycode_filter").val() ) {
521                 searched += _(" with category ") + "'" + $("#categorycode_filter").find("option:selected").text() + "'";
522             }
523             if ( $("#branchcode_filter").val() ) {
524                 searched += _(" in library ") + $("#branchcode_filter").find("option:selected").text();
525             }
526             $("#searchpattern").text(searched);
527         }
528
529         // Redraw the table
530         function filter() {
531             $("#firstletter_filter").val('');
532             update_searched();
533             search = 1;
534             $("#searchresults").show();
535             dtMemberResults.fnDraw();
536             return false;
537         }
538
539         // User has clicked on the Clear button
540         function clearFilters(redraw) {
541             $("#searchform select").val('');
542             $("#firstletter_filter").val('');
543             $("#searchmember_filter").val('');
544             if(redraw) {
545                 search = 1;
546                 $("#searchresults").show();
547                 dtMemberResults.fnDraw();
548             }
549         }
550
551         // User has clicked on a letter
552         function filterByFirstLetterSurname(letter) {
553             clearFilters(false);
554             $("#firstletter_filter").val(letter);
555             update_searched();
556             search = 1;
557             $("#searchresults").show();
558             dtMemberResults.fnDraw();
559         }
560     </script>
561 [% END %]
562
563 [% INCLUDE 'intranet-bottom.inc' %]