8 [% INCLUDE 'doc-head-open.inc' %]
9 [% SET libraries = Branches.all %]
10 [% SET categories = Categories.all.unblessed %]
11 <title>Patron search › Koha</title>
12 [% INCLUDE 'doc-head-close.inc' %]
13 <style> .modal-body .close { display: none; } </style>
16 <body id="common_patron_search" class="common">
17 <div id="patron_search" class="yui-t7">
18 <div class="container-fluid">
20 <form id="searchform">
21 <fieldset class="brief">
22 <h3>Search for patron</h3>
25 <label for="searchmember_filter">Search:</label>
26 <input type="text" id="searchmember_filter" value="[% searchmember | html %]" class="focus" />
29 [% FOR column IN columns %]
33 <label for="branchcode_filter">Library:</label>
34 <select id="branchcode_filter">
35 [% SET libraries = Branches.all( only_from_group => 1 ) %]
36 [% IF libraries.size != 1 %]
37 <option value="">Any</option>
39 [% FOREACH l IN libraries %]
40 <option value="[% l.branchcode | html %]">[% l.branchname | html %]</option>
46 <label for="categorycode_filter">Category:</label>
47 <select id="categorycode_filter">
48 <option value="">Any</option>
49 [% FOREACH category IN categories %]
50 <option value="[% category.categorycode | html %]">[% category.description | html %]</option>
57 <fieldset class="action">
58 <input type="submit" value="Search" />
63 [% IF filter == 'suggestions_managers' %]
64 <div class="hint">Only staff with superlibrarian or suggestions_manage permissions are returned in the search results</div>
65 [% ELSIF filter == 'orders_managers' %]
66 <div class="hint">Only staff with superlibrarian or acquisitions permissions (or order_manage permission if granular permissions are enabled) are returned in the search results</div>
67 [% ELSIF filter == 'funds_owners' OR filter == 'funds_users' %]
68 <div class="hint">Only staff with superlibrarian or acquisitions permissions (or budget_modify permission if granular permissions are enabled) are returned in the search results</div>
73 [% FOREACH letter IN alphabet.split(' ') %]
74 <a href="#" class="filterByLetter">[% letter | html %]</a>
78 <div id="info" class="dialog message" style="display: none;"></div>
79 <div id="error" class="dialog alert" style="dispay: none;"></div>
81 <input type="hidden" id="firstletter_filter" value="" />
82 <div id="searchresults" style="display:none;">
83 <table id="memberresultst">
86 [% FOR column IN columns %]
88 [% CASE 'cardnumber' %]<th>Card</th>
89 [% CASE 'dateofbirth' %]<th>Date of birth</th>
90 [% CASE 'address' %]<th>Address</th>
91 [% CASE 'name' %]<th>Name</th>
92 [% CASE 'branch' %]<th data-filter="libraries">Library</th>
93 [% CASE 'category' %]<th data-filter="categories">Category</th>
94 [% CASE 'dateexpiry' %]<th>Expires on</td>
95 [% CASE 'borrowernotes' %]<th>Notes</th>
96 [% CASE 'action' %]<th> </th>
105 <div id="closewindow"><a href="#" class="btn btn-default btn-default close">Close</a></div>
107 <!-- Patron preview modal -->
108 <div class="modal" id="patronPreview" tabindex="-1" role="dialog" aria-labelledby="patronPreviewLabel">
109 <div class="modal-dialog" role="document">
110 <div class="modal-content">
111 <div class="modal-header">
112 <button type="button" class="closebtn" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
113 <h4 class="modal-title" id="patronPreviewLabel"></h4>
115 <div class="modal-body">
117 <img src="[% interface | html %]/[% theme | html %]/img/spinner-small.gif" alt="" /> Loading
120 <div class="modal-footer">
121 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
130 [% MACRO jsinclude BLOCK %]
132 let categories = [% To.json(categories) | $raw %];
133 let categories_map = categories.reduce((map, c) => {
134 map[c.categorycode] = c;
137 let libraries = [% To.json(libraries) | $raw %];
138 let libraries_map = libraries.reduce((map, l) => {
139 map[l.branchcode] = l;
143 [% IF Koha.Preference('ExtendedPatronAttributes') %]
144 let extended_attribute_types = [% To.json(attribute_type_codes || []) | $raw %];
147 [% INCLUDE 'datatables.inc' %]
148 [% INCLUDE 'js-date-format.inc' %]
149 [% INCLUDE 'js-patron-get-age.inc' %]
150 [% INCLUDE 'js-patron-format.inc' %]
151 [% INCLUDE 'js-patron-format-address.inc' %]
156 $(document).ready(function(){
160 $("#searchresults").hide();
162 let additional_filters = {
164 let start_with = $("#firstletter_filter").val()
165 if (!start_with) return "";
166 return { "like": start_with + "%" }
169 let filter = $("#searchmember_filter").val();
170 if (!filter) return "";
171 [% SET search_fields = Koha.Preference('DefaultPatronSearchFields') || 'surname,firstname,othernames,cardnumber,userid' %]
173 [% FOR search_field IN search_fields.split(',') %]
174 {"me.[% search_field %]":{"like":"%"+filter+"%"}},
176 [% IF Koha.Preference('ExtendedPatronAttributes') %]
178 "extended_attributes.value": { "like": "%" + filter + "%" },
179 "extended_attributes.code": extended_attribute_types
185 [% SET default_sort_column = "name" %]
186 [% SET order_column_index = 0 %]
187 patrons_table = $("#memberresultst").kohaTable({
190 [% CASE 'suggestions_managers' %]
191 "url": '/api/v1/suggestions/managers'
192 [% CASE 'baskets_managers' %]
193 "url": '/api/v1/acquisitions/baskets/managers'
194 [% CASE 'funds_owners' %]
195 "url": '/api/v1/acquisitions/funds/owners'
196 [% CASE 'funds_users' %]
197 "url": '/api/v1/acquisitions/funds/users'
199 "url": '/api/v1/patrons'
202 embed: ['extended_attributes'],
205 [% FOR column IN columns %]
206 [% IF default_sort_column == column %]
207 [% order_column_index = loop.count - 1%]
210 [% CASE 'cardnumber' %]
212 "data": "cardnumber",
216 [% CASE 'dateofbirth' %]
218 "data": "date_of_birth",
221 "render": function( data, type, row, meta ) {
222 return data ? escape_str($date(data) + " (" + _("%s years").format($get_age(data)) + ")") : "";
227 "data": "me.street_number:me.address:me.address2:me.city:me.state:me.postal_code:me.country",
230 "render": function( data, type, row, meta ) {
231 return escape_str($format_address(row) + " ") + escape_str(libraries_map[row.library_id].branchname);
236 "data": "me.firstname:me.surname:me.othernames",
239 "render": function( data, type, row, meta ) {
240 let patron_id = encodeURIComponent(row.patron_id);
241 return "<a href=\"/cgi-bin/koha/members/moremember.pl?borrowernumber=" + patron_id + "\" class=\"patron_preview\" data-borrowernumber=\"" + patron_id + "\" style=\"white-space:nowrap\">" + $patron_to_html(row, { invert_name: 1 }) + "</a>";
246 "data": "library_id",
249 "render": function( data, type, row, meta ) {
250 return escape_str(libraries_map[data].branchname);
253 [% CASE 'category' %]
255 "data": "category_id",
258 "render": function( data, type, row, meta ) {
259 return escape_str(categories_map[data].description);
262 [% CASE 'dateexpiry' %]
264 "data": "expiry_date",
267 "render": function( data, type, row, meta ) {
268 return data ? escape_str($date(data)) : "";
271 [% CASE 'borrowernotes' %]
273 "data": "staff_notes",
276 [%# We don't escape here, we allow html tag in staff notes %]
280 "data": function( row, type, val, meta ) {
282 let patron_id = encodeURIComponent(row.patron_id);
283 [% IF selection_type == 'select' %]
284 return '<a href="#" class="btn btn-default btn-xs select_user" data-borrowernumber="' + patron_id + '">Select</a><input type="hidden" id="borrower_data' + patron_id + '" name="borrower_data'+ patron_id + '" value=\''+JSON.stringify(row)+'\' />';
286 return '<a href="#" class="btn btn-default btn-xs add_user" data-borrowernumber="' + patron_id + '" data-firstname="' + encodeURIComponent(row.firstname) + '" data-surname="' + encodeURIComponent(row.surname) + '">Add</a><input type="hidden" id="borrower_data' + patron_id + '" name="borrower_data'+ patron_id + '" />';
293 [% UNLESS loop.last %],[% END %]
296 "order": [[ [% order_column_index %], "asc" ]],
298 'sPaginationType': 'full_numbers',
299 "iDisplayLength": [% Koha.Preference('PatronsPerPage') | html %],
300 }, null, 1, additional_filters);
302 $("#searchform").on('submit', filter);
303 $(".filterByLetter").on("click",function(e){
305 filterByFirstLetterSurname($(this).text());
307 $("body").on("click",".add_user",function(e){
309 var borrowernumber = $(this).data("borrowernumber");
310 var firstname = $(this).data("firstname");
311 var surname = $(this).data("surname");
312 add_user( borrowernumber, firstname + " " + surname );
315 $("body").on("click",".select_user",function(e){
317 var borrowernumber = $(this).data("borrowernumber");
318 var borrower_data = $("#borrower_data"+borrowernumber).val();
319 select_user( borrowernumber, JSON.parse(borrower_data) );
322 $("body").on("click",".patron_preview", function( e ){
324 var borrowernumber = $(this).data("borrowernumber");
325 var page = "/cgi-bin/koha/members/moremember.pl?print=brief&borrowernumber=" + borrowernumber;
326 $("#patronPreview .modal-body").load( page + " div.container-fluid" );
327 $('#patronPreview').modal({show:true});
330 $("#patronPreview").on('hidden.bs.modal', function (e) {
331 $("#patronPreview .modal-body").html("<img src=\"[% interface | html %]/[% theme | html %]/img/spinner-small.gif\" alt=\"\" /> Loading");
338 $("#firstletter_filter").val('');
339 $("#searchresults").show();
341 let table_dt = patrons_table.DataTable();
342 [% FOR c IN columns %]
345 let library_id = $("#branchcode_filter").val();
346 patrons_table.find('thead tr:eq(1) th[data-filter="libraries"] select').val(library_id);
347 table_dt.column([% loop.count - 1 %]).search(library_id ? '^'+library_id+'$' : '');
348 [% CASE 'category' %]
349 let category_id = $("#categorycode_filter").val();
350 patrons_table.find('thead tr:eq(1) th[data-filter="categories"] select').val(category_id);
351 table_dt.column([% loop.count - 1 %]).search(category_id ? '^'+category_id+'$' : '');
359 // User has clicked on a letter
360 function filterByFirstLetterSurname(letter) {
361 $("#firstletter_filter").val(letter);
363 $("#searchresults").show();
364 patrons_table.fnDraw();
367 // modify parent window owner element
368 [% IF selection_type == 'add' %]
369 function add_user(borrowernumber, borrowername) {
370 var p = window.opener;
371 // In one place (serials/routing.tt), the page is reload on every add
372 // We have to wait for the page to be there
373 function wait_for_opener () {
374 if ( ! $(opener.document).find('body').size() ) {
375 setTimeout(wait_for_opener, 500);
377 [%# Note that add_user could sent data instead of borrowername too %]
380 if ( p.add_user(borrowernumber, borrowername) < 0 ) {
381 $("#error").html(_("Patron '%s' is already in the list.").format(borrowername));
384 $("#info").html(_("Patron '%s' added.").format(borrowername));
391 [% ELSIF selection_type == 'select' %]
392 function select_user(borrowernumber, data) {
393 var p = window.opener;
395 p.[% callback | html %](borrowernumber, data);
397 p.select_user(borrowernumber, data);
405 [% SET popup_window = 1 %]
406 [% INCLUDE 'intranet-bottom.inc' %]