Line 0
Link Here
|
|
|
1 |
[% USE Koha %] |
2 |
[% USE Branches %] |
3 |
[% USE raw %] |
4 |
[% USE To %] |
5 |
|
6 |
[% BLOCK patron_search_filters_simple %] |
7 |
<form id="patron_search_form"> |
8 |
<div class="hint">Enter patron card number or partial name:</div> |
9 |
<input type="text" size="40" id="search_patron_filter" class="focus" autocomplete="off" /> |
10 |
<input type="submit" value="Search" /> |
11 |
</form> |
12 |
[% END %] |
13 |
|
14 |
[% BLOCK patron_search_filters %] |
15 |
<form id="patron_search_form"> |
16 |
<fieldset class="brief"> |
17 |
<h3>Search for patron</h3> |
18 |
<ol> |
19 |
<li> |
20 |
<label for="search_patron_filter">Search:</label> |
21 |
<div class="hint">Enter patron card number or partial name:</div> |
22 |
<input type="text" id="search_patron_filter" value="[% search_filter | html %]" class="focus" /> |
23 |
</li> |
24 |
|
25 |
[% FOR column IN columns %] |
26 |
[% SWITCH column %] |
27 |
[% CASE 'branch' %] |
28 |
<li> |
29 |
<label for="branchcode_filter">Library:</label> |
30 |
<select id="branchcode_filter"> |
31 |
[% SET libraries = Branches.all( only_from_group => 1 ) %] |
32 |
[% IF libraries.size != 1 %] |
33 |
<option value="">Any</option> |
34 |
[% END %] |
35 |
[% FOREACH l IN libraries %] |
36 |
<option value="[% l.branchcode | html %]">[% l.branchname | html %]</option> |
37 |
[% END %] |
38 |
</select> |
39 |
</li> |
40 |
[% CASE 'category' %] |
41 |
<li> |
42 |
<label for="categorycode_filter">Category:</label> |
43 |
<select id="categorycode_filter"> |
44 |
<option value="">Any</option> |
45 |
[% FOREACH category IN categories %] |
46 |
<option value="[% category.categorycode | html %]">[% category.description | html %]</option> |
47 |
[% END %] |
48 |
</select> |
49 |
</li> |
50 |
[% END %] |
51 |
[% END %] |
52 |
</ol> |
53 |
<fieldset class="action"> |
54 |
<input type="submit" value="Search" /> |
55 |
</fieldset> |
56 |
</fieldset> |
57 |
</form> |
58 |
[% END %] |
59 |
|
60 |
[% BLOCK patron_search_table %] |
61 |
|
62 |
[% IF filter == 'suggestions_managers' %] |
63 |
<div class="hint">Only staff with superlibrarian or suggestions_manage permissions are returned in the search results</div> |
64 |
[% ELSIF filter == 'orders_managers' %] |
65 |
<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> |
66 |
[% ELSIF filter == 'funds_owners' OR filter == 'funds_users' %] |
67 |
<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> |
68 |
[% END %] |
69 |
|
70 |
<div class="browse"> |
71 |
Browse by last name: |
72 |
[% SET alphabet = Koha.Preference('alphabet').split(' ') %] |
73 |
[% UNLESS alphabet.size %] |
74 |
[% alphabet = ['A' .. 'Z'] %] |
75 |
[% END %] |
76 |
[% FOREACH letter IN alphabet %] |
77 |
<a href="#" class="filterByLetter">[% letter | html %]</a> |
78 |
[% END %] |
79 |
</div> |
80 |
|
81 |
<div id="[% table_id %]_search_results" style="display:none;"> |
82 |
|
83 |
<div id="info" class="dialog message" style="display: none;"></div> |
84 |
<div id="error" class="dialog alert" style="dispay: none;"></div> |
85 |
|
86 |
|
87 |
<input type="hidden" id="firstletter_filter" value="" /> |
88 |
[% IF open_on_row_click %] |
89 |
<table id="[% table_id %]" class="selections-table"> |
90 |
[% ELSE %] |
91 |
<table id="[% table_id %]"> |
92 |
[% END %] |
93 |
<thead> |
94 |
<tr> |
95 |
[% FOR column IN columns %] |
96 |
[% SWITCH column %] |
97 |
[% CASE 'cardnumber' %]<th>Card</th> |
98 |
[% CASE 'dateofbirth' %]<th>Date of birth</th> |
99 |
[% CASE 'name' %]<th>Name</th> |
100 |
[% CASE 'name-address' %]<th>Name</th> |
101 |
[% CASE 'address' %]<th>Address</th> |
102 |
[% CASE 'address-library' %]<th>Address</th> |
103 |
[% CASE 'branch' %]<th data-filter="libraries">Library</th> |
104 |
[% CASE 'category' %]<th data-filter="categories">Category</th> |
105 |
[% CASE 'dateexpiry' %]<th>Expires on</td> |
106 |
[% CASE 'borrowernotes' %]<th>Notes</th> |
107 |
[% CASE 'phone' %]<th>Phone</th> |
108 |
[% CASE 'action' %]<th> </th> |
109 |
[% END %] |
110 |
[% END %] |
111 |
</tr> |
112 |
</thead> |
113 |
<tbody></tbody> |
114 |
</table> |
115 |
</div> |
116 |
|
117 |
<!-- Patron preview modal --> |
118 |
<div class="modal" id="patronPreview" tabindex="-1" role="dialog" aria-labelledby="patronPreviewLabel"> |
119 |
<div class="modal-dialog" role="document"> |
120 |
<div class="modal-content"> |
121 |
<div class="modal-header"> |
122 |
<button type="button" class="closebtn" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> |
123 |
<h4 class="modal-title" id="patronPreviewLabel"></h4> |
124 |
</div> |
125 |
<div class="modal-body"> |
126 |
<div id="loading"> |
127 |
<img src="[% interface | html %]/[% theme | html %]/img/spinner-small.gif" alt="" /> Loading |
128 |
</div> |
129 |
</div> |
130 |
<div class="modal-footer"> |
131 |
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button> |
132 |
</div> |
133 |
</div> |
134 |
</div> |
135 |
</div> |
136 |
|
137 |
[% END %] |
138 |
|
139 |
[% BLOCK patron_search_js %] |
140 |
|
141 |
[% IF redirect_if_one_result && !redirect_url %] |
142 |
<script>console.log("Wrong call of patron_searh_js - missing redirect_url");</script> |
143 |
[% END %] |
144 |
<script> |
145 |
let categories = [% To.json(categories) | $raw %]; |
146 |
let categories_map = categories.reduce((map, c) => { |
147 |
map[c.categorycode] = c; |
148 |
return map; |
149 |
}, {}); |
150 |
let libraries = [% To.json(libraries) | $raw %]; |
151 |
let libraries_map = libraries.reduce((map, l) => { |
152 |
map[l.branchcode] = l; |
153 |
return map; |
154 |
}, {}); |
155 |
|
156 |
[% IF Koha.Preference('ExtendedPatronAttributes') %] |
157 |
let extended_attribute_types = [% To.json(attribute_type_codes || []) | $raw %]; |
158 |
[% END %] |
159 |
|
160 |
</script> |
161 |
|
162 |
[% INCLUDE 'datatables.inc' %] |
163 |
[% INCLUDE 'js-date-format.inc' %] |
164 |
[% INCLUDE 'js-patron-get-age.inc' %] |
165 |
[% INCLUDE 'js-patron-format.inc' %] |
166 |
[% INCLUDE 'js-patron-format-address.inc' %] |
167 |
|
168 |
<script> |
169 |
var first_draw = 0; |
170 |
let patrons_table; |
171 |
|
172 |
$(document).ready(function(){ |
173 |
|
174 |
|
175 |
$("#info").hide(); |
176 |
$("#error").hide(); |
177 |
|
178 |
let additional_filters = { |
179 |
surname: function(){ |
180 |
let start_with = $("#firstletter_filter").val() |
181 |
if (!start_with) return ""; |
182 |
return { "like": start_with + "%" } |
183 |
}, |
184 |
"-and": function(){ |
185 |
let filter = $("#searchmember_filter").val(); |
186 |
if (!filter) return ""; |
187 |
[% SET search_fields = Koha.Preference('DefaultPatronSearchFields') || 'surname,firstname,othernames,cardnumber,userid' %] |
188 |
return [ |
189 |
[% FOR search_field IN search_fields.split(',') %] |
190 |
{"me.[% search_field %]":{"like":"%"+filter+"%"}}, |
191 |
[% END %] |
192 |
[% IF Koha.Preference('ExtendedPatronAttributes') %] |
193 |
{ |
194 |
"extended_attributes.value": { "like": "%" + filter + "%" }, |
195 |
"extended_attributes.code": extended_attribute_types |
196 |
} |
197 |
[% END %] |
198 |
]; |
199 |
} |
200 |
}; |
201 |
patrons_table = $("#[% table_id %]").kohaTable({ |
202 |
"ajax": { |
203 |
[% SWITCH filter %] |
204 |
[% CASE 'suggestions_managers' %] |
205 |
"url": '/api/v1/suggestions/managers', |
206 |
[% CASE 'baskets_managers' %] |
207 |
"url": '/api/v1/acquisitions/baskets/managers', |
208 |
[% CASE 'funds_owners' %] |
209 |
"url": '/api/v1/acquisitions/funds/owners', |
210 |
[% CASE 'funds_users' %] |
211 |
"url": '/api/v1/acquisitions/funds/users', |
212 |
[% CASE %] |
213 |
"url": '/api/v1/patrons', |
214 |
[% END %] |
215 |
"dataSrc": function ( json ) { |
216 |
[% IF redirect_if_one_result %] |
217 |
// redirect if there is only 1 result. |
218 |
if ( first_draw && json.recordsFiltered == 1 ) { |
219 |
document.location.href = '[% redirect_url %]&borrowernumber=' + json.data[0].patron_id; |
220 |
return false; |
221 |
} |
222 |
first_draw = 0; |
223 |
[% END %] |
224 |
return json.data; |
225 |
} |
226 |
}, |
227 |
embed: ['extended_attributes'], |
228 |
"drawCallback": function( settings ) { |
229 |
var api = this.api(); |
230 |
var data = api.data(); |
231 |
if ( data.length == 0 ) return; |
232 |
|
233 |
[% IF open_on_row_click %] |
234 |
$.each($(this).find("tbody tr"), function(index, tr) { |
235 |
let url = "[% on_click_url %]&borrowernumber=" + data[index].patron_id; |
236 |
$(tr).off('click').on('click', function() { |
237 |
document.location.href = url; |
238 |
}).addClass('clickable'); |
239 |
$(tr).find("a.patron_name").attr('href', url); |
240 |
}); |
241 |
[% ELSE %] |
242 |
$.each($(this).find("tbody tr"), function(index, tr) { |
243 |
$(tr).find("a.patron_name").addClass("patron_preview"); |
244 |
}); |
245 |
[% END %] |
246 |
}, |
247 |
"order": [[ 1, "asc" ]], |
248 |
"iDeferLoading": 0, |
249 |
"columns": [ |
250 |
[% FOR column IN columns %] |
251 |
[% SWITCH column %] |
252 |
[% CASE 'cardnumber' %] |
253 |
{ |
254 |
"data": "cardnumber", |
255 |
"searchable": true, |
256 |
"orderable": true |
257 |
} |
258 |
[% CASE 'dateofbirth' %] |
259 |
{ |
260 |
"data": "date_of_birth", |
261 |
"searchable": true, |
262 |
"orderable": true, |
263 |
"render": function( data, type, row, meta ) { |
264 |
return data ? escape_str($date(data) + " (" + _("%s years").format($get_age(data)) + ")") : ""; |
265 |
} |
266 |
} |
267 |
[% CASE 'address' %] |
268 |
{ |
269 |
"data": "me.street_number:me.address:me.address2:me.city:me.state:me.postal_code:me.country", |
270 |
"searchable": true, |
271 |
"orderable": true, |
272 |
"render": function( data, type, row, meta ) { |
273 |
let r = '<div class="address"><ul>'; |
274 |
r += $format_address(row, { no_line_break: 1 }); |
275 |
r += '</div></ul>'; |
276 |
return r; |
277 |
} |
278 |
} |
279 |
[% CASE 'address-library' %] |
280 |
{ |
281 |
"data": "me.street_number:me.address:me.address2:me.city:me.state:me.postal_code:me.country", |
282 |
"searchable": true, |
283 |
"orderable": true, |
284 |
"render": function( data, type, row, meta ) { |
285 |
let r = '<div class="address"><ul>'; |
286 |
r += $format_address(row, { no_line_break: 1 }); |
287 |
r += '</div></ul>'; |
288 |
r += " " + escape_str(libraries_map[row.library_id].branchname); |
289 |
return r; |
290 |
} |
291 |
} |
292 |
[% CASE 'name-address' %] |
293 |
{ |
294 |
"data": "me.firstname:me.surname:me.othernames:me.street_number:me.address:me.address2:me.city:me.state:me.postal_code:me.country", |
295 |
"searchable": true, |
296 |
"orderable": true, |
297 |
"render": function( data, type, row, meta ) { |
298 |
let patron_id = encodeURIComponent(row.patron_id); |
299 |
let r = ''; |
300 |
[% IF ! open_on_row_click %] |
301 |
r += "<a href=\"/cgi-bin/koha/members/moremember.pl?borrowernumber=" + patron_id + "\" class=\"patron_name\" data-borrowernumber=\"" + patron_id + "\" style=\"white-space:nowrap\">" + $patron_to_html(row, { invert_name: 1 }) + "</a>"; |
302 |
[% ELSE %] |
303 |
r += $patron_to_html(row, { invert_name: 1 }); |
304 |
[% END %] |
305 |
r += '<br/>'; |
306 |
r += '<div class="address"><ul>'; |
307 |
r += $format_address(row, { no_line_break: 1 }); |
308 |
|
309 |
if ( row.email ) { |
310 |
r += "<li>" + _("Email: ") + "<a href='mailto:" + encodeURIComponent(row.email) + "'>" + escape_str(row.email) + "</a></li>"; |
311 |
} |
312 |
r += '</ul></div>' |
313 |
|
314 |
return r; |
315 |
} |
316 |
} |
317 |
[% CASE 'name' %] |
318 |
{ |
319 |
"data": "me.firstname:me.surname:me.othernames", |
320 |
"searchable": true, |
321 |
"orderable": true, |
322 |
"render": function( data, type, row, meta ) { |
323 |
let patron_id = encodeURIComponent(row.patron_id); |
324 |
return "<a href=\"/cgi-bin/koha/members/moremember.pl?borrowernumber=" + patron_id + "\" class=\"patron_name\" data-borrowernumber=\"" + patron_id + "\" style=\"white-space:nowrap\">" + $patron_to_html(row, { invert_name: 1 }) + "</a>"; |
325 |
} |
326 |
} |
327 |
[% CASE 'branch' %] |
328 |
{ |
329 |
"data": "library_id", |
330 |
"searchable": true, |
331 |
"orderable": true, |
332 |
"render": function( data, type, row, meta ) { |
333 |
return escape_str(libraries_map[data].branchname); |
334 |
} |
335 |
} |
336 |
[% CASE 'category' %] |
337 |
{ |
338 |
"data": "category_id", |
339 |
"searchable": true, |
340 |
"orderable": true, |
341 |
"render": function( data, type, row, meta ) { |
342 |
return escape_str(categories_map[data].description); |
343 |
} |
344 |
} |
345 |
[% CASE 'dateexpiry' %] |
346 |
{ |
347 |
"data": "expiry_date", |
348 |
"searchable": true, |
349 |
"orderable": true, |
350 |
"render": function( data, type, row, meta ) { |
351 |
return data ? escape_str($date(data)) : ""; |
352 |
} |
353 |
} |
354 |
[% CASE 'borrowernotes' %] |
355 |
{ |
356 |
"data": "staff_notes", |
357 |
"searchable": true, |
358 |
"orderable": true, |
359 |
[%# We don't escape here, we allow html tag in staff notes %] |
360 |
} |
361 |
[% CASE 'phone' %] |
362 |
{ |
363 |
"data": "phone", |
364 |
"searchable": true, |
365 |
"orderable": true, |
366 |
"render": function( data, type, row, meta ) { |
367 |
return escape_str(data); |
368 |
} |
369 |
} |
370 |
[% CASE 'action' %] |
371 |
{ |
372 |
"data": function( row, type, val, meta ) { |
373 |
|
374 |
let patron_id = encodeURIComponent(row.patron_id); |
375 |
[% IF selection_type == 'select' %] |
376 |
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)+'\' />'; |
377 |
[% ELSE %] |
378 |
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 + '" />'; |
379 |
[% END %] |
380 |
}, |
381 |
"searchable": false, |
382 |
"orderable": false |
383 |
} |
384 |
[% END %] |
385 |
[% UNLESS loop.last %],[% END %] |
386 |
[% END %] |
387 |
], |
388 |
'bAutoWidth': false, |
389 |
'sPaginationType': 'full_numbers', |
390 |
"iDisplayLength": [% Koha.Preference('PatronsPerPage') | html %], |
391 |
}, typeof table_settings !== 'undefined' ? table_settings : null, 1, additional_filters); |
392 |
|
393 |
$("#patron_search_form").on('submit', filter); |
394 |
$(".filterByLetter").on("click",function(e){ |
395 |
e.preventDefault(); |
396 |
filterByFirstLetterSurname($(this).text()); |
397 |
}); |
398 |
$("body").on("click",".add_user",function(e){ |
399 |
e.preventDefault(); |
400 |
var borrowernumber = $(this).data("borrowernumber"); |
401 |
var firstname = $(this).data("firstname"); |
402 |
var surname = $(this).data("surname"); |
403 |
add_user( borrowernumber, firstname + " " + surname ); |
404 |
}); |
405 |
|
406 |
$("body").on("click",".select_user",function(e){ |
407 |
e.preventDefault(); |
408 |
var borrowernumber = $(this).data("borrowernumber"); |
409 |
var borrower_data = $("#borrower_data"+borrowernumber).val(); |
410 |
select_user( borrowernumber, JSON.parse(borrower_data) ); |
411 |
}); |
412 |
|
413 |
$("body").on("click",".patron_preview", function( e ){ |
414 |
e.preventDefault(); |
415 |
var borrowernumber = $(this).data("borrowernumber"); |
416 |
var page = "/cgi-bin/koha/members/moremember.pl?print=brief&borrowernumber=" + borrowernumber; |
417 |
$("#patronPreview .modal-body").load( page + " div.container-fluid" ); |
418 |
$('#patronPreview').modal({show:true}); |
419 |
}); |
420 |
|
421 |
$("#patronPreview").on('hidden.bs.modal', function (e) { |
422 |
$("#patronPreview .modal-body").html("<img src=\"[% interface | html %]/[% theme | html %]/img/spinner-small.gif\" alt=\"\" /> Loading"); |
423 |
}); |
424 |
|
425 |
}); |
426 |
|
427 |
function filter() { |
428 |
$("#firstletter_filter").val(''); |
429 |
$("#[% table_id %]_search_results").show(); |
430 |
|
431 |
let table_dt = patrons_table.DataTable(); |
432 |
[% FOR c IN columns %] |
433 |
[% SWITCH c %] |
434 |
[% CASE 'branch' %] |
435 |
library_id = $("#branchcode_filter").val() || ""; |
436 |
patrons_table.find('thead tr:eq(1) th[data-filter="libraries"] select').val(library_id); |
437 |
table_dt.column([% loop.count - 1 %]).search(library_id); |
438 |
[% CASE 'category' %] |
439 |
let category_id = $("#categorycode_filter").val() || ""; |
440 |
patrons_table.find('thead tr:eq(1) th[data-filter="categories"] select').val(category_id); |
441 |
table_dt.column([% loop.count - 1 %]).search(category_id); |
442 |
[% END %] |
443 |
[% END %] |
444 |
table_dt.search(""); |
445 |
first_draw = 1; // Only redirect if we are coming from here |
446 |
table_dt.draw(); |
447 |
return false; |
448 |
} |
449 |
|
450 |
// User has clicked on a letter |
451 |
function filterByFirstLetterSurname(letter) { |
452 |
$("#firstletter_filter").val(letter); |
453 |
$("#[% table_id %]_search_results").show(); |
454 |
patrons_table.DataTable().draw(); |
455 |
} |
456 |
|
457 |
// modify parent window owner element |
458 |
[% IF selection_type == 'add' %] |
459 |
function add_user(borrowernumber, borrowername) { |
460 |
var p = window.opener; |
461 |
// In one place (serials/routing.tt), the page is reload on every add |
462 |
// We have to wait for the page to be there |
463 |
function wait_for_opener () { |
464 |
if ( ! $(opener.document).find('body').size() ) { |
465 |
setTimeout(wait_for_opener, 500); |
466 |
} else { |
467 |
[%# Note that add_user could sent data instead of borrowername too %] |
468 |
$("#info").hide(); |
469 |
$("#error").hide(); |
470 |
if ( p.add_user(borrowernumber, borrowername) < 0 ) { |
471 |
$("#error").html(_("Patron '%s' is already in the list.").format(borrowername)); |
472 |
$("#error").show(); |
473 |
} else { |
474 |
$("#info").html(_("Patron '%s' added.").format(borrowername)); |
475 |
$("#info").show(); |
476 |
} |
477 |
} |
478 |
} |
479 |
wait_for_opener(); |
480 |
} |
481 |
[% ELSIF selection_type == 'select' %] |
482 |
function select_user(borrowernumber, data) { |
483 |
var p = window.opener; |
484 |
[% IF callback %] |
485 |
p.[% callback | html %](borrowernumber, data); |
486 |
[% ELSE %] |
487 |
p.select_user(borrowernumber, data); |
488 |
[% END %] |
489 |
window.close(); |
490 |
} |
491 |
[% END %] |
492 |
</script> |
493 |
[% END %] |