Line 0
Link Here
|
|
|
1 |
[% USE raw %] |
2 |
[% USE To %] |
3 |
[% USE Asset %] |
4 |
[% USE Koha %] |
5 |
[% USE Branches %] |
6 |
[% USE Categories %] |
7 |
[% SET footerjs = 1 %] |
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> |
14 |
</head> |
15 |
|
16 |
<body id="common_patron_search" class="common"> |
17 |
<div id="patron_search" class="yui-t7"> |
18 |
<div class="container-fluid"> |
19 |
|
20 |
<form id="searchform"> |
21 |
<fieldset class="brief"> |
22 |
<h3>Search for patron</h3> |
23 |
<ol> |
24 |
<li> |
25 |
<label for="searchmember_filter">Search:</label> |
26 |
<input type="text" id="searchmember_filter" value="[% searchmember | html %]" class="focus" /> |
27 |
</li> |
28 |
|
29 |
[% FOR column IN columns %] |
30 |
[% SWITCH column %] |
31 |
[% CASE 'branch' %] |
32 |
<li> |
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> |
38 |
[% END %] |
39 |
[% FOREACH l IN libraries %] |
40 |
<option value="[% l.branchcode | html %]">[% l.branchname | html %]</option> |
41 |
[% END %] |
42 |
</select> |
43 |
</li> |
44 |
[% CASE 'category' %] |
45 |
<li> |
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> |
51 |
[% END %] |
52 |
</select> |
53 |
</li> |
54 |
[% END %] |
55 |
[% END %] |
56 |
</ol> |
57 |
<fieldset class="action"> |
58 |
<input type="submit" value="Search" /> |
59 |
</fieldset> |
60 |
</fieldset> |
61 |
</form> |
62 |
|
63 |
[% IF patrons_with_acq_perm_only %] |
64 |
<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> |
65 |
[% END %] |
66 |
|
67 |
[% IF patrons_with_suggestion_perm_only %] |
68 |
<div class="hint">Only staff with superlibrarian or suggestions_manage permissions are returned in the search results</div> |
69 |
[% END %] |
70 |
|
71 |
<div class="browse"> |
72 |
Browse by last name: |
73 |
[% FOREACH letter IN alphabet.split(' ') %] |
74 |
<a href="#" class="filterByLetter">[% letter | html %]</a> |
75 |
[% END %] |
76 |
</div> |
77 |
|
78 |
<div id="info" class="dialog message"></div> |
79 |
<div id="error" class="dialog alert"></div> |
80 |
|
81 |
<input type="hidden" id="firstletter_filter" value="" /> |
82 |
<div id="searchresults"> |
83 |
<table id="memberresultst"> |
84 |
<thead> |
85 |
<tr> |
86 |
[% FOR column IN columns %] |
87 |
[% SWITCH column %] |
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> |
97 |
[% END %] |
98 |
[% END %] |
99 |
</tr> |
100 |
</thead> |
101 |
<tbody></tbody> |
102 |
</table> |
103 |
</div> |
104 |
|
105 |
<div id="closewindow"><a href="#" class="btn btn-default btn-default close">Close</a></div> |
106 |
|
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> |
114 |
</div> |
115 |
<div class="modal-body"> |
116 |
<div id="loading"> |
117 |
<img src="[% interface | html %]/[% theme | html %]/img/spinner-small.gif" alt="" /> Loading |
118 |
</div> |
119 |
</div> |
120 |
<div class="modal-footer"> |
121 |
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button> |
122 |
</div> |
123 |
</div> |
124 |
</div> |
125 |
</div> |
126 |
|
127 |
</div> |
128 |
</div> |
129 |
|
130 |
[% MACRO jsinclude BLOCK %] |
131 |
<script> |
132 |
let categories = [% To.json(categories) | $raw %]; |
133 |
let categories_map = categories.reduce((map, c) => { |
134 |
map[c.categorycode] = c; |
135 |
return map; |
136 |
}, {}); |
137 |
let libraries = [% To.json(libraries) | $raw %]; |
138 |
let libraries_map = libraries.reduce((map, l) => { |
139 |
map[l.branchcode] = l; |
140 |
return map; |
141 |
}, {}); |
142 |
</script> |
143 |
[% INCLUDE 'datatables.inc' %] |
144 |
[% INCLUDE 'js-date-format.inc' %] |
145 |
[% INCLUDE 'js-patron-get-age.inc' %] |
146 |
[% INCLUDE 'js-patron-format.inc' %] |
147 |
[% INCLUDE 'js-patron-format-address.inc' %] |
148 |
|
149 |
<script> |
150 |
var search = 0; |
151 |
let patrons_table; |
152 |
$(document).ready(function(){ |
153 |
$("#info").hide(); |
154 |
$("#error").hide(); |
155 |
|
156 |
$("#searchresults").hide(); |
157 |
|
158 |
let additional_filters = { |
159 |
surname: function(){ |
160 |
let start_with = $("#firstletter_filter").val() |
161 |
if (!start_with) return ""; |
162 |
return { "like": start_with + "%" } |
163 |
} |
164 |
}; |
165 |
patrons_table = $("#memberresultst").kohaTable({ |
166 |
"ajax": { |
167 |
"url": '/api/v1/patrons' |
168 |
}, |
169 |
"order": [[ 1, "asc" ]], |
170 |
"iDeferLoading": 0, |
171 |
"columns": [ |
172 |
[% FOR column IN columns %] |
173 |
[% SWITCH column %] |
174 |
[% CASE 'cardnumber' %] |
175 |
{ |
176 |
"data": "cardnumber", |
177 |
"searchable": true, |
178 |
"orderable": true |
179 |
} |
180 |
[% CASE 'dateofbirth' %] |
181 |
{ |
182 |
"data": "date_of_birth", |
183 |
"searchable": true, |
184 |
"orderable": true, |
185 |
"render": function( data, type, row, meta ) { |
186 |
return data ? escape_str($date(data) + " (" + _("%s years").format($get_age(data)) + ")") : ""; |
187 |
} |
188 |
} |
189 |
[% CASE 'address' %] |
190 |
{ |
191 |
"data": "me.street_number:me.address:me.address2:me.city:me.state:me.postal_code:me.country", |
192 |
"searchable": true, |
193 |
"orderable": true, |
194 |
"render": function( data, type, row, meta ) { |
195 |
return escape_str($format_address(row) + " ") + escape_str(libraries_map[row.library_id].branchname); |
196 |
} |
197 |
} |
198 |
[% CASE 'name' %] |
199 |
{ |
200 |
"data": "me.firstname:me.surname", |
201 |
"searchable": true, |
202 |
"orderable": true, |
203 |
"render": function( data, type, row, meta ) { |
204 |
return $patron_to_html(row, { invert_name: 1 }); |
205 |
} |
206 |
} |
207 |
[% CASE 'branch' %] |
208 |
{ |
209 |
"data": "library_id", |
210 |
"searchable": true, |
211 |
"orderable": true, |
212 |
"render": function( data, type, row, meta ) { |
213 |
return escape_str(libraries_map[data].branchname); |
214 |
} |
215 |
} |
216 |
[% CASE 'category' %] |
217 |
{ |
218 |
"data": "category_id", |
219 |
"searchable": true, |
220 |
"orderable": true, |
221 |
"render": function( data, type, row, meta ) { |
222 |
return escape_str(categories_map[data].description); |
223 |
} |
224 |
} |
225 |
[% CASE 'dateexpiry' %] |
226 |
{ |
227 |
"data": "expiry_date", |
228 |
"searchable": true, |
229 |
"orderable": true, |
230 |
"render": function( data, type, row, meta ) { |
231 |
return data ? escape_str($date(data)) : ""; |
232 |
} |
233 |
} |
234 |
[% CASE 'borrowernotes' %] |
235 |
{ |
236 |
"data": "staff_notes", |
237 |
"searchable": true, |
238 |
"orderable": true, |
239 |
[%# We don't escape here, we allow html tag in staff notes %] |
240 |
} |
241 |
[% CASE 'action' %] |
242 |
{ |
243 |
"data": function( row, type, val, meta ) { |
244 |
|
245 |
let patron_id = encodeURIComponent(row.patron_id); |
246 |
[% IF selection_type == 'select' %] |
247 |
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)+'\' />'; |
248 |
[% ELSE %] |
249 |
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 + '" />'; |
250 |
[% END %] |
251 |
}, |
252 |
"searchable": false, |
253 |
"orderable": false |
254 |
} |
255 |
[% END %] |
256 |
[% UNLESS loop.last %],[% END %] |
257 |
[% END %] |
258 |
], |
259 |
'bAutoWidth': false, |
260 |
'sPaginationType': 'full_numbers', |
261 |
"iDisplayLength": [% Koha.Preference('PatronsPerPage') | html %], |
262 |
}, null, 1, additional_filters); |
263 |
|
264 |
$("#searchform").on('submit', filter); |
265 |
$(".filterByLetter").on("click",function(e){ |
266 |
e.preventDefault(); |
267 |
filterByFirstLetterSurname($(this).text()); |
268 |
}); |
269 |
$("body").on("click",".add_user",function(e){ |
270 |
e.preventDefault(); |
271 |
var borrowernumber = $(this).data("borrowernumber"); |
272 |
var firstname = $(this).data("firstname"); |
273 |
var surname = $(this).data("surname"); |
274 |
add_user( borrowernumber, firstname + " " + surname ); |
275 |
}); |
276 |
|
277 |
$("body").on("click",".select_user",function(e){ |
278 |
e.preventDefault(); |
279 |
var borrowernumber = $(this).data("borrowernumber"); |
280 |
var borrower_data = $("#borrower_data"+borrowernumber).val(); |
281 |
select_user( borrowernumber, JSON.parse(borrower_data) ); |
282 |
}); |
283 |
|
284 |
$("body").on("click",".patron_preview", function( e ){ |
285 |
e.preventDefault(); |
286 |
var borrowernumber = $(this).data("borrowernumber"); |
287 |
var page = "/cgi-bin/koha/members/moremember.pl?print=brief&borrowernumber=" + borrowernumber; |
288 |
$("#patronPreview .modal-body").load( page + " div.container-fluid" ); |
289 |
$('#patronPreview').modal({show:true}); |
290 |
}); |
291 |
|
292 |
$("#patronPreview").on('hidden.bs.modal', function (e) { |
293 |
$("#patronPreview .modal-body").html("<img src=\"[% interface | html %]/[% theme | html %]/img/spinner-small.gif\" alt=\"\" /> Loading"); |
294 |
}); |
295 |
|
296 |
}); |
297 |
|
298 |
function filter() { |
299 |
search = 1; |
300 |
$("#firstletter_filter").val(''); |
301 |
$("#searchresults").show(); |
302 |
|
303 |
let table_dt = patrons_table.DataTable(); |
304 |
[% FOR c IN columns %] |
305 |
[% SWITCH c %] |
306 |
[% CASE 'branch' %] |
307 |
let library_id = $("#branchcode_filter").val(); |
308 |
patrons_table.find('thead tr:eq(1) th[data-filter="libraries"] select').val(library_id); |
309 |
table_dt.column([% loop.count - 1 %]).search(library_id); |
310 |
[% CASE 'category' %] |
311 |
let category_id = $("#categorycode_filter").val(); |
312 |
patrons_table.find('thead tr:eq(1) th[data-filter="categories"] select').val(category_id); |
313 |
table_dt.column([% loop.count - 1 %]).search(category_id); |
314 |
[% END %] |
315 |
[% END %] |
316 |
table_dt.search($("#searchmember_filter").val()); |
317 |
table_dt.draw(); |
318 |
return false; |
319 |
} |
320 |
|
321 |
// User has clicked on a letter |
322 |
function filterByFirstLetterSurname(letter) { |
323 |
$("#firstletter_filter").val(letter); |
324 |
search = 1; |
325 |
$("#searchresults").show(); |
326 |
patrons_table.fnDraw(); |
327 |
} |
328 |
|
329 |
// modify parent window owner element |
330 |
[% IF selection_type == 'add' %] |
331 |
function add_user(borrowernumber, borrowername) { |
332 |
var p = window.opener; |
333 |
// In one place (serials/routing.tt), the page is reload on every add |
334 |
// We have to wait for the page to be there |
335 |
function wait_for_opener () { |
336 |
if ( ! $(opener.document).find('body').size() ) { |
337 |
setTimeout(wait_for_opener, 500); |
338 |
} else { |
339 |
[%# Note that add_user could sent data instead of borrowername too %] |
340 |
$("#info").hide(); |
341 |
$("#error").hide(); |
342 |
if ( p.add_user(borrowernumber, borrowername) < 0 ) { |
343 |
$("#error").html(_("Patron '%s' is already in the list.").format(borrowername)); |
344 |
$("#error").show(); |
345 |
} else { |
346 |
$("#info").html(_("Patron '%s' added.").format(borrowername)); |
347 |
$("#info").show(); |
348 |
} |
349 |
} |
350 |
} |
351 |
wait_for_opener(); |
352 |
} |
353 |
[% ELSIF selection_type == 'select' %] |
354 |
function select_user(borrowernumber, data) { |
355 |
var p = window.opener; |
356 |
[% IF callback %] |
357 |
p.[% callback | html %](borrowernumber, data); |
358 |
[% ELSE %] |
359 |
p.select_user(borrowernumber, data); |
360 |
[% END %] |
361 |
window.close(); |
362 |
} |
363 |
[% END %] |
364 |
</script> |
365 |
[% END %] |
366 |
|
367 |
[% SET popup_window = 1 %] |
368 |
[% INCLUDE 'intranet-bottom.inc' %] |