View | Details | Raw Unified | Return to bug 26597
Collapse All | Expand All

(-)a/C4/Utils/DataTables/Members.pm (+317 lines)
Line 0 Link Here
1
package C4::Utils::DataTables::Members;
2
3
use Modern::Perl;
4
use C4::Context;
5
use C4::Utils::DataTables;
6
use Koha::DateUtils;
7
8
sub search {
9
    my ( $params ) = @_;
10
    my $searchmember = $params->{searchmember};
11
    my $firstletter = $params->{firstletter};
12
    my $categorycode = $params->{categorycode};
13
    my $branchcode = $params->{branchcode};
14
    my $searchtype = $params->{searchtype} || 'contain';
15
    my $searchfieldstype = $params->{searchfieldstype} || 'standard';
16
    my $has_permission = $params->{has_permission};
17
    my $dt_params = $params->{dt_params};
18
19
    unless ( $searchmember ) {
20
        $searchmember = $dt_params->{sSearch} // '';
21
    }
22
23
    # If branches are independent and user is not superlibrarian
24
    # The search has to be only on the user branch
25
    my $userenv = C4::Context->userenv;
26
    my $logged_in_user = Koha::Patrons->find( $userenv->{number} );
27
    my @restricted_branchcodes = $logged_in_user->libraries_where_can_see_patrons;
28
29
    my ($sth, $query, $iTotalQuery, $iTotalRecords, $iTotalDisplayRecords);
30
    my $dbh = C4::Context->dbh;
31
32
    # Get the module_bit from a given permission code
33
    if ( $has_permission ) {
34
        ($has_permission->{module_bit}) = $dbh->selectrow_array(q|
35
            SELECT bit FROM userflags WHERE flag=?
36
        |, undef, $has_permission->{permission});
37
    }
38
39
    my (@where, @conditions);
40
    # Get the iTotalRecords DataTable variable
41
    $iTotalQuery = "SELECT COUNT(borrowers.borrowernumber) FROM borrowers";
42
    if ( $has_permission ) {
43
        $iTotalQuery .= ' LEFT JOIN user_permissions ON borrowers.borrowernumber=user_permissions.borrowernumber';
44
        $iTotalQuery .= ' AND module_bit=? AND code=?';
45
        push @conditions, $has_permission->{module_bit}, $has_permission->{subpermission};
46
    }
47
48
    if ( @restricted_branchcodes ) {
49
        push @where, "borrowers.branchcode IN (" . join( ',', ('?') x @restricted_branchcodes ) . ")";
50
        push @conditions, @restricted_branchcodes;
51
    }
52
    if ( $has_permission ) {
53
        push @where, '( borrowers.flags = 1 OR borrowers.flags & (1 << ?) OR module_bit=? AND code=? )';
54
        push @conditions, ($has_permission->{module_bit}) x 2, $has_permission->{subpermission};
55
    }
56
    $iTotalQuery .= ' WHERE ' . join ' AND ', @where if @where;
57
    ($iTotalRecords) = $dbh->selectrow_array( $iTotalQuery, undef, @conditions );
58
59
    # Do that after iTotalQuery!
60
    if ( defined $branchcode and $branchcode ) {
61
        @restricted_branchcodes = @restricted_branchcodes
62
            ? grep ({ $_ eq $branchcode } @restricted_branchcodes)
63
                ? ($branchcode)
64
                : (undef) # Do not return any results
65
            : ($branchcode);
66
    }
67
68
    if ( $searchfieldstype eq 'dateofbirth' ) {
69
        # Return an empty list if the date of birth is not correctly formatted
70
        $searchmember = eval { output_pref( { str => $searchmember, dateformat => 'iso', dateonly => 1 } ); };
71
        if ( $@ or not $searchmember ) {
72
            return {
73
                iTotalRecords        => $iTotalRecords,
74
                iTotalDisplayRecords => 0,
75
                patrons              => [],
76
            };
77
        }
78
    }
79
80
    my @columns = qw( borrowernumber surname firstname othernames flags streetnumber streettype address address2 city state zipcode country cardnumber dateexpiry borrowernotes branchcode email userid dateofbirth categorycode phone phonepro mobile fax email emailpro);
81
82
    my $prefillguarantorfields = C4::Context->preference("PrefillGuaranteeField");
83
    my @prefill_fields = split(/\,/,$prefillguarantorfields);
84
    if ( @prefill_fields ) {
85
        foreach my $field (@prefill_fields) {
86
            if (! grep {$_ eq $field} @columns) {
87
                push @columns, $field;
88
            }
89
        }
90
    };
91
92
    my $borrowers_columns = "";
93
    foreach my $item (@columns) {
94
        $borrowers_columns .= "borrowers." . $item . ", ";
95
    }
96
97
    my $select = "SELECT " . $borrowers_columns . "
98
        categories.description AS category_description, categories.category_type,
99
        branches.branchname, borrowers.phone";
100
    my $from = "FROM borrowers
101
                LEFT JOIN branches ON borrowers.branchcode = branches.branchcode
102
                LEFT JOIN categories ON borrowers.categorycode = categories.categorycode";
103
    my @where_args;
104
    if ( $has_permission ) {
105
        $from .= '
106
                LEFT JOIN user_permissions ON borrowers.borrowernumber=user_permissions.borrowernumber
107
                AND module_bit=? AND code=?';
108
        push @where_args, $has_permission->{module_bit}, $has_permission->{subpermission};
109
    }
110
    my @where_strs;
111
    if(defined $firstletter and $firstletter ne '') {
112
        push @where_strs, "borrowers.surname LIKE ?";
113
        push @where_args, "$firstletter%";
114
    }
115
    if(defined $categorycode and $categorycode ne '') {
116
        push @where_strs, "borrowers.categorycode = ?";
117
        push @where_args, $categorycode;
118
    }
119
    if(@restricted_branchcodes ) {
120
        push @where_strs, "borrowers.branchcode IN (" . join( ',', ('?') x @restricted_branchcodes ) . ")";
121
        push @where_args, @restricted_branchcodes;
122
    }
123
124
    my $searchfields = {
125
        standard => C4::Context->preference('DefaultPatronSearchFields') || 'surname,firstname,othernames,cardnumber,userid',
126
        email => 'email,emailpro,B_email',
127
        borrowernumber => 'borrowernumber',
128
        phone => 'phone,phonepro,B_phone,altcontactphone,mobile',
129
        address => 'streetnumber,streettype,address,address2,city,state,zipcode,country',
130
    };
131
132
    # * is replaced with % for sql
133
    $searchmember =~ s/\*/%/g;
134
135
    # split into search terms
136
    my @terms;
137
    # consider coma as space
138
    $searchmember =~ s/,/ /g;
139
    if ( $searchtype eq 'contain' ) {
140
       @terms = split / /, $searchmember;
141
    } else {
142
       @terms = ($searchmember);
143
    }
144
145
    foreach my $term (@terms) {
146
        next unless $term;
147
148
        my $term_dt = eval { local $SIG{__WARN__} = {}; output_pref( { str => $term, dateonly => 1, dateformat => 'sql' } ); };
149
150
        if ($term_dt) {
151
            $term = $term_dt;
152
        } else {
153
            $term .= '%'    # end with anything
154
              if $term !~ /%$/;
155
            $term = "%$term"    # begin with anythin unless start_with
156
              if $searchtype eq 'contain' && $term !~ /^%/;
157
        }
158
159
        my @where_strs_or;
160
        if ( defined $searchfields->{$searchfieldstype} ) {
161
            for my $searchfield ( split /,/, $searchfields->{$searchfieldstype} ) {
162
                push @where_strs_or, "borrowers." . $dbh->quote_identifier($searchfield) . " LIKE ?";
163
                push @where_args, $term;
164
            }
165
        } else {
166
            push @where_strs_or, "borrowers." . $dbh->quote_identifier($searchfieldstype) . " LIKE ?";
167
            push @where_args, $term;
168
        }
169
170
171
        if ( $searchfieldstype eq 'standard' and C4::Context->preference('ExtendedPatronAttributes') and $searchmember ) {
172
            my @matching_borrowernumbers = Koha::Patrons->filter_by_attribute_value($searchmember)->get_column('borrowernumber');
173
174
            for my $borrowernumber ( @matching_borrowernumbers ) {
175
                push @where_strs_or, "borrowers.borrowernumber = ?";
176
                push @where_args, $borrowernumber;
177
            }
178
        }
179
180
        push @where_strs, '('. join (' OR ', @where_strs_or) . ')'
181
            if @where_strs_or;
182
    }
183
184
    if ( $has_permission ) {
185
        push @where_strs, '( borrowers.flags = 1 OR borrowers.flags & (1 << ?) OR module_bit=? AND code=? )';
186
        push @where_args, ($has_permission->{module_bit}) x 2, $has_permission->{subpermission};
187
    }
188
189
    my $where = @where_strs ? " WHERE " . join (" AND ", @where_strs) : undef;
190
    my $orderby = dt_build_orderby($dt_params);
191
192
    my $limit;
193
    # If iDisplayLength == -1, we want to display all patrons
194
    if ( !$dt_params->{iDisplayLength} || $dt_params->{iDisplayLength} > -1 ) {
195
        # In order to avoid sql injection
196
        $dt_params->{iDisplayStart} =~ s/\D//g if defined($dt_params->{iDisplayStart});
197
        $dt_params->{iDisplayLength} =~ s/\D//g if defined($dt_params->{iDisplayLength});
198
        $dt_params->{iDisplayStart} //= 0;
199
        $dt_params->{iDisplayLength} //= 20;
200
        $limit = "LIMIT $dt_params->{iDisplayStart},$dt_params->{iDisplayLength}";
201
    }
202
203
    $query = join(
204
        " ",
205
        ($select ? $select : ""),
206
        ($from ? $from : ""),
207
        ($where ? $where : ""),
208
        ($orderby ? $orderby : ""),
209
        ($limit ? $limit : "")
210
    );
211
    $sth = $dbh->prepare($query);
212
    $sth->execute(@where_args);
213
    my $patrons = $sth->fetchall_arrayref({});
214
215
    # Get the iTotalDisplayRecords DataTable variable
216
    $query = "SELECT COUNT(borrowers.borrowernumber) " . $from . ($where ? $where : "");
217
    $sth = $dbh->prepare($query);
218
    $sth->execute(@where_args);
219
    ($iTotalDisplayRecords) = $sth->fetchrow_array;
220
221
    # Get some information on patrons
222
    foreach my $patron (@$patrons) {
223
        my $patron_object = Koha::Patrons->find( $patron->{borrowernumber} );
224
        $patron->{overdues} = $patron_object->get_overdues->count;
225
        $patron->{issues} = $patron_object->checkouts->count;
226
        $patron->{age} = $patron_object->get_age;
227
        my $balance = $patron_object->account->balance;
228
        # FIXME Should be formatted from the template
229
        $patron->{fines} = sprintf("%.2f", $balance);
230
231
        if( $patron->{dateexpiry} ) {
232
            # FIXME We should not format the date here, do it in template-side instead
233
            $patron->{dateexpiry} = output_pref( { dt => scalar dt_from_string( $patron->{dateexpiry}, 'iso'), dateonly => 1} );
234
        } else {
235
            $patron->{dateexpiry} = '';
236
        }
237
    }
238
239
    return {
240
        iTotalRecords => $iTotalRecords,
241
        iTotalDisplayRecords => $iTotalDisplayRecords,
242
        patrons => $patrons
243
    }
244
}
245
246
1;
247
__END__
248
249
=head1 NAME
250
251
C4::Utils::DataTables::Members - module for using DataTables with patrons
252
253
=head1 SYNOPSIS
254
255
This module provides (one for the moment) routines used by the patrons search
256
257
=head2 FUNCTIONS
258
259
=head3 search
260
261
    my $dt_infos = C4::Utils::DataTables::Members->search($params);
262
263
$params is a hashref with some keys:
264
265
=over 4
266
267
=item searchmember
268
269
  String to search in the borrowers sql table
270
271
=item firstletter
272
273
  Introduced to contain 1 letter but can contain more.
274
  The search will done on the borrowers.surname field
275
276
=item categorycode
277
278
  Search patrons with this categorycode
279
280
=item branchcode
281
282
  Search patrons with this branchcode
283
284
=item searchtype
285
286
  Can be 'start_with' or 'contain' (default value). Used for the searchmember parameter.
287
288
=item searchfieldstype
289
290
  Can be 'standard' (default value), 'email', 'borrowernumber', 'phone', 'address' or 'dateofbirth', 'sort1', 'sort2'
291
292
=item dt_params
293
294
  Is the reference of C4::Utils::DataTables::dt_get_params($input);
295
296
=cut
297
298
=back
299
300
=head1 LICENSE
301
302
This file is part of Koha.
303
304
Copyright 2013 BibLibre
305
306
Koha is free software; you can redistribute it and/or modify it
307
under the terms of the GNU General Public License as published by
308
the Free Software Foundation; either version 3 of the License, or
309
(at your option) any later version.
310
311
Koha is distributed in the hope that it will be useful, but
312
WITHOUT ANY WARRANTY; without even the implied warranty of
313
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
314
GNU General Public License for more details.
315
316
You should have received a copy of the GNU General Public License
317
along with Koha; if not, see <http://www.gnu.org/licenses>.
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref (-1 / +1 lines)
Lines 298-304 Patrons: Link Here
298
           class: multi
298
           class: multi
299
         - (input multiple choices separated by |). Leave empty to deactivate.
299
         - (input multiple choices separated by |). Leave empty to deactivate.
300
     -
300
     -
301
         - "When adding a guarantee to a guarantor patron fill the following fields in the guarantee's member entry form from the guarantors record:"
301
         - "When adding a guarantor relationship to a patron fill the following unfilled fields in the guarantee's member entry form from the guarantors record:"
302
         - pref: PrefillGuaranteeField
302
         - pref: PrefillGuaranteeField
303
           multiple:
303
           multiple:
304
               B_streettype: "Alternate address - Street type"
304
               B_streettype: "Alternate address - Street type"
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/common/patron_search.tt (+300 lines)
Line 0 Link Here
1
[% USE raw %]
2
[% USE Asset %]
3
[% USE Koha %]
4
[% USE Branches %]
5
[% SET footerjs = 1 %]
6
[% INCLUDE 'doc-head-open.inc' %]
7
<title>Koha &rsaquo; Patron search</title>
8
[% INCLUDE 'doc-head-close.inc' %]
9
<style> .modal-body .close { display: none; } </style>
10
</head>
11
12
<body id="common_patron_search" class="common">
13
<div id="patron_search" class="yui-t7">
14
    <div class="container-fluid">
15
16
        <form id="searchform">
17
            <fieldset class="brief">
18
                <h3>Search for patron</h3>
19
                <ol>
20
                    <li>
21
                        <label for="searchmember_filter">Search:</label>
22
                        <input type="text" id="searchmember_filter" value="[% searchmember | html %]"/>
23
                    </li>
24
                    <li>
25
                        <label for="categorycode_filter">Category:</label>
26
                        <select id="categorycode_filter">
27
                            <option value="">Any</option>
28
                            [% FOREACH category IN categories %]
29
                                <option value="[% category.categorycode | html %]">[% category.description | html %]</option>
30
                            [% END %]
31
                        </select>
32
                    </li>
33
                    <li>
34
                        <label for="branchcode_filter">Library:</label>
35
                        <select id="branchcode_filter">
36
                            [% SET libraries = Branches.all( only_from_group => 1 ) %]
37
                            [% IF libraries.size != 1 %]
38
                                <option value="">Any</option>
39
                            [% END %]
40
                            [% FOREACH l IN libraries %]
41
                                <option value="[% l.branchcode | html %]">[% l.branchname | html %]</option>
42
                            [% END %]
43
                        </select>
44
                    </li>
45
                </ol>
46
                <fieldset class="action">
47
                    <input type="submit" value="Search" />
48
                </fieldset>
49
            </fieldset>
50
        </form>
51
52
        [% IF patrons_with_acq_perm_only %]
53
            <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>
54
        [% END %]
55
56
        [% IF patrons_with_suggestion_perm_only %]
57
            <div class="hint">Only staff with superlibrarian or suggestions_manage permissions are returned in the search results</div>
58
        [% END %]
59
60
        <div class="browse">
61
            Browse by last name:
62
            [% FOREACH letter IN alphabet.split(' ') %]
63
                <a href="#" class="filterByLetter">[% letter | html %]</a>
64
            [% END %]
65
        </div>
66
67
        <div id="info" class="dialog message"></div>
68
        <div id="error" class="dialog alert"></div>
69
70
        <input type="hidden" id="firstletter_filter" value="" />
71
        <div id="searchresults">
72
            <table id="memberresultst">
73
                <thead>
74
                    <tr>
75
                        [% FOR column IN columns %]
76
                            [% SWITCH column %]
77
                                [% CASE 'cardnumber' %]<th>Card</th>
78
                                [% CASE 'dateofbirth' %]<th>Date of birth</th>
79
                                [% CASE 'address' %]<th>Address</th>
80
                                [% CASE 'name' %]<th>Name</th>
81
                                [% CASE 'branch' %]<th>Library</th>
82
                                [% CASE 'category' %]<th>Category</th>
83
                                [% CASE 'dateexpiry' %]<th>Expires on</td>
84
                                [% CASE 'borrowernotes' %]<th>Notes</th>
85
                                [% CASE 'action' %]<th>&nbsp;</th>
86
                            [% END %]
87
                        [% END %]
88
                    </tr>
89
                  </thead>
90
                <tbody></tbody>
91
            </table>
92
        </div>
93
94
<div id="closewindow"><a href="#" class="btn btn-default btn-default close">Close</a></div>
95
96
<!-- Patron preview modal -->
97
<div class="modal" id="patronPreview" tabindex="-1" role="dialog" aria-labelledby="patronPreviewLabel">
98
    <div class="modal-dialog" role="document">
99
        <div class="modal-content">
100
            <div class="modal-header">
101
                <button type="button" class="closebtn" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
102
                <h4 class="modal-title" id="patronPreviewLabel"></h4>
103
            </div>
104
            <div class="modal-body">
105
                <div id="loading">
106
                    <img src="[% interface | html %]/[% theme | html %]/img/spinner-small.gif" alt="" /> Loading
107
                </div>
108
            </div>
109
            <div class="modal-footer">
110
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
111
            </div>
112
        </div>
113
    </div>
114
</div>
115
116
</div>
117
</div>
118
119
[% MACRO jsinclude BLOCK %]
120
    [% INCLUDE 'datatables.inc' %]
121
122
    <script type="text/javascript">
123
        var search = 1;
124
        $(document).ready(function(){
125
            $("#info").hide();
126
            $("#error").hide();
127
128
            [% IF view != "show_results" %]
129
                $("#searchresults").hide();
130
                search = 0;
131
            [% END %]
132
133
            // Apply DataTables on the results table
134
            dtMemberResults = $("#memberresultst").dataTable($.extend(true, {}, dataTablesDefaults, {
135
                'bServerSide': true,
136
                'sAjaxSource': "/cgi-bin/koha/svc/members/search",
137
                'fnServerData': function(sSource, aoData, fnCallback) {
138
                    if ( ! search ) {
139
                        return;
140
                    }
141
                    aoData.push({
142
                        'name': 'searchmember',
143
                        'value': $("#searchmember_filter").val()
144
                    },{
145
                        'name': 'firstletter',
146
                        'value': $("#firstletter_filter").val()
147
                    },{
148
                        'name': 'categorycode',
149
                        'value': $("#categorycode_filter").val()
150
                    },{
151
                        'name': 'branchcode',
152
                        'value': $("#branchcode_filter").val()
153
                    },{
154
                        'name': 'name_sorton',
155
                        'value': 'borrowers.surname borrowers.firstname'
156
                    },{
157
                        'name': 'category_sorton',
158
                        'value': 'categories.description',
159
                    },{
160
                        'name': 'branch_sorton',
161
                        'value': 'branches.branchname'
162
                    },{
163
                        'name': 'template_path',
164
                        'value': '[% json_template | html %]',
165
                    },{
166
                        'name': 'selection_type',
167
                        'value': '[% selection_type | html %]',
168
                    }
169
                    [% IF patrons_with_acq_perm_only %]
170
                    ,{
171
                        'name': 'has_permission',
172
                        'value': 'acquisition.order_manage',
173
                    }
174
                    [% ELSIF patrons_with_suggestion_perm_only %]
175
                    ,{
176
                        'name': 'has_permission',
177
                        'value': 'suggestions.suggestions_manage',
178
                    }
179
                    [% END %]
180
                    );
181
                    $.ajax({
182
                        'dataType': 'json',
183
                        'type': 'POST',
184
                        'url': sSource,
185
                        'data': aoData,
186
                        'success': function(json){
187
                            fnCallback(json);
188
                        }
189
                    });
190
                },
191
                'aoColumns':[
192
                    [% FOR column IN columns %]
193
                        [% IF column == 'action' %]
194
                            { 'mDataProp': 'dt_action', 'bSortable': false, 'sClass': 'actions' }
195
                        [% ELSIF column == 'address' %]
196
                            { 'mDataProp': 'dt_address', 'bSortable': false }
197
                        [% ELSE %]
198
                            { 'mDataProp': 'dt_[% column | html %]' }
199
                        [% END %]
200
                        [% UNLESS loop.last %],[% END %]
201
                    [% END %]
202
                ],
203
                'bAutoWidth': false,
204
                'sPaginationType': 'full_numbers',
205
                "iDisplayLength": [% Koha.Preference('PatronsPerPage') | html %],
206
                'aaSorting': [[[% aaSorting || 0 | html %], 'asc']],
207
                'bFilter': false,
208
                'bProcessing': true,
209
            }));
210
211
            $("#searchform").on('submit', filter);
212
            $(".filterByLetter").on("click",function(e){
213
                e.preventDefault();
214
                filterByFirstLetterSurname($(this).text());
215
            });
216
            $("body").on("click",".add_user",function(e){
217
                e.preventDefault();
218
                var borrowernumber = $(this).data("borrowernumber");
219
                var firstname = $(this).data("firstname");
220
                var surname = $(this).data("surname");
221
                add_user( borrowernumber, firstname + " " + surname );
222
            });
223
224
            $("body").on("click",".select_user",function(e){
225
                e.preventDefault();
226
                var borrowernumber = $(this).data("borrowernumber");
227
                var borrower_data = $("#borrower_data"+borrowernumber).val();
228
                var guarantor_attributes = $("#guarantor_attributes"+borrowernumber).val();
229
                if ( !guarantor_attributes ) {
230
                    guarantor_attributes = "{}";
231
                }
232
                select_user( borrowernumber, JSON.parse(borrower_data), JSON.parse(guarantor_attributes) );
233
            });
234
235
            $("body").on("click",".patron_preview", function( e ){
236
                e.preventDefault();
237
                var borrowernumber = $(this).data("borrowernumber");
238
                var page = "/cgi-bin/koha/members/moremember.pl?print=brief&borrowernumber=" + borrowernumber;
239
                $("#patronPreview .modal-body").load( page + " div.container-fluid" );
240
                $('#patronPreview').modal({show:true});
241
            });
242
243
            $("#patronPreview").on('hidden.bs.modal', function (e) {
244
                $("#patronPreview .modal-body").html("<img src=\"[% interface | html %]/[% theme | html %]/img/spinner-small.gif\" alt=\"\" /> Loading");
245
            });
246
247
        });
248
249
        function filter() {
250
            search = 1;
251
            $("#firstletter_filter").val('');
252
            $("#searchresults").show();
253
            dtMemberResults.fnDraw();
254
            return false;
255
        }
256
257
        // User has clicked on a letter
258
        function filterByFirstLetterSurname(letter) {
259
            $("#firstletter_filter").val(letter);
260
            search = 1;
261
            $("#searchresults").show();
262
            dtMemberResults.fnDraw();
263
        }
264
265
        // modify parent window owner element
266
        [% IF selection_type == 'add' %]
267
            function add_user(borrowernumber, borrowername) {
268
                var p = window.opener;
269
                // In one place (serials/routing.tt), the page is reload on every add
270
                // We have to wait for the page to be there
271
                function wait_for_opener () {
272
                    if ( ! $(opener.document).find('body').size() ) {
273
                        setTimeout(wait_for_opener, 500);
274
                    } else {
275
                        [%# Note that add_user could sent data instead of borrowername too %]
276
                        $("#info").hide();
277
                        $("#error").hide();
278
                        if ( p.add_user(borrowernumber, borrowername) < 0 ) {
279
                            $("#error").html(_("Patron '%s' is already in the list.").format(borrowername));
280
                            $("#error").show();
281
                        } else {
282
                            $("#info").html(_("Patron '%s' added.").format(borrowername));
283
                            $("#info").show();
284
                        }
285
                    }
286
                }
287
                wait_for_opener();
288
            }
289
        [% ELSIF selection_type == 'select' %]
290
            function select_user(borrowernumber, data, attributes) {
291
                var p = window.opener;
292
                p.select_user(borrowernumber, data, null, attributes);
293
                window.close();
294
            }
295
        [% END %]
296
    </script>
297
[% END %]
298
299
[% SET popup_window = 1 %]
300
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt (-1 / +1 lines)
Lines 1772-1778 legend:hover { Link Here
1772
1772
1773
            [% IF new_guarantors %]
1773
            [% IF new_guarantors %]
1774
                [% FOREACH g IN new_guarantors %]
1774
                [% FOREACH g IN new_guarantors %]
1775
                    select_user( '[% g.patron.borrowernumber | html %]', [% To.json( g.patron.unblessed ) | $raw %], '[% g.relationship | html %]' );
1775
                    select_user( '[% g.patron.borrowernumber | html %]', [% To.json( g.patron.unblessed ) | $raw %], '[% g.relationship | html %]' [% IF guarantor_attributes %], [% To.json( guarantor_attributes ) | $raw %][% END %] );
1776
                [% END %]
1776
                [% END %]
1777
            [% END %]
1777
            [% END %]
1778
1778
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/tables/guarantor_search.tt (+36 lines)
Line 0 Link Here
1
[% USE raw %]
2
[% USE To %]
3
[% USE Branches %]
4
[% USE KohaDates %]
5
{
6
    "sEcho": [% sEcho | html %],
7
    "iTotalRecords": [% iTotalRecords | html %],
8
    "iTotalDisplayRecords": [% iTotalDisplayRecords | html %],
9
    "aaData": [
10
        [% FOREACH data IN aaData %]
11
            {
12
                "dt_cardnumber":
13
                    "[% data.cardnumber | html %]",
14
                "dt_name":
15
                    "[% INCLUDE 'patron-title.inc' borrowernumber = data.borrowernumber category_type = data.category_type firstname = data.firstname surname = data.surname othernames = data.othernames cardnumber = data.cardnumber invert_name = 1%]",
16
                "dt_dateofbirth":
17
                    "[% INCLUDE 'patron-age.inc' patron = data %]",
18
                "dt_address":
19
                    "[% INCLUDE escape_address data=data %]",
20
                "dt_action":
21
                    "<a href=\"#\" class=\"btn btn-default btn-xs select_user\" data-borrowernumber=\"[% data.borrowernumber | html %]\">Select</a><input type=\"hidden\" id=\"borrower_data[% data.borrowernumber | html %]\" name=\"borrower_data[% data.borrowernumber | html %]\" value=\"[% To.json(data) | html %]\" /><input type=\"hidden\" id=\"guarantor_attributes[% data.borrowernumber | html %]\" name=\"guarantor_attributes[% data.borrowernumber | html %]\" value=\"[% To.json(guarantor_attributes) | html %]\" />"
22
            }[% UNLESS loop.last %],[% END %]
23
        [% END %]
24
    ]
25
}
26
[% BLOCK escape_address %]
27
[%~ SET address = data.streetnumber _ ' ' %]
28
[%~ IF data.address %][% SET address = address _ data.address _ ' ' %][% END %]
29
[%~ IF data.address2 %][% SET address = address _ data.address2 _ ' ' %][% END %]
30
[%~ IF data.city %][% SET address = address _ data.city _ ' ' %][% END %]
31
[%~ IF data.state %][% SET address = address _ data.state _ ' ' %][% END %]
32
[%~ IF data.zipcode %][% SET address = address _ data.zipcode _ ' ' %][% END %]
33
[%~ IF data.country %][% SET address = address _ data.country _ ' ' %][% END %]
34
[%~ SET address = address _ Branches.GetName( data.branchcode ) %]
35
[%~ To.json( address ) | $raw ~%]
36
[% END %]
(-)a/koha-tmpl/intranet-tmpl/prog/js/members.js (-2 / +11 lines)
Lines 76-83 function update_category_code(category_code) { Link Here
76
    hint.html(hint_string);
76
    hint.html(hint_string);
77
}
77
}
78
78
79
function select_user(borrowernumber, borrower, relationship) {
79
function select_user(borrowernumber, borrower, relationship, attributes) {
80
    let is_guarantor = $(`.guarantor-details[data-borrowernumber=${borrowernumber}]`).length;
80
    let is_guarantor = $(`.guarantor-details[data-borrowernumber=${borrower.borrowernumber}]`).length;
81
81
82
    if ( is_guarantor ) {
82
    if ( is_guarantor ) {
83
        alert("Patron is already a guarantor for this patron");
83
        alert("Patron is already a guarantor for this patron");
Lines 121-126 function select_user(borrowernumber, borrower, relationship) { Link Here
121
        if ( relationship ) {
121
        if ( relationship ) {
122
            fieldset.find('.new_guarantor_relationship').val(relationship);
122
            fieldset.find('.new_guarantor_relationship').val(relationship);
123
        }
123
        }
124
125
        if ( attributes ) {
126
            for (var i = 0; i < parseInt(attributes.length, 10); i++) {
127
                var attribute = attributes[i];
128
                if ( borrower[attribute] != null && document.forms.entryform[attribute].value == "" ) {
129
                    document.forms.entryform[attribute].value = borrower[attribute];
130
                }
131
            }
132
        }
124
    }
133
    }
125
134
126
    return 0;
135
    return 0;
(-)a/svc/members/search (-1 / +153 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/perl
2
3
# Copyright 2013 BibLibre
4
#
5
# This file is part of Koha
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
use CGI;
22
23
use C4::Auth qw( get_template_and_user haspermission get_user_subpermissions );
24
use C4::Output qw( output_with_http_headers );
25
use C4::Utils::DataTables qw( dt_get_params );
26
use C4::Utils::DataTables::Members qw( search );
27
use Koha::DateUtils qw( output_pref dt_from_string );
28
use Koha::Patrons;
29
30
my $input = CGI->new;
31
32
exit unless $input->param('template_path');
33
34
my ($template, $user, $cookie) = get_template_and_user({
35
    template_name   => scalar $input->param('template_path'),
36
    query           => $input,
37
    type            => "intranet",
38
    flagsrequired   => { borrowers => 'edit_borrowers' }
39
});
40
41
my $searchmember = $input->param('searchmember');
42
my $firstletter  = $input->param('firstletter');
43
my $categorycode = $input->param('categorycode');
44
my $branchcode = $input->param('branchcode');
45
my $searchtype = $input->param('searchtype');
46
my $searchfieldstype = $input->param('searchfieldstype') || 'standard';
47
my $has_permission = $input->param('has_permission');
48
my $selection_type = $input->param('selection_type');
49
50
# variable information for DataTables (id)
51
my $sEcho = $input->param('sEcho');
52
53
my %dt_params = dt_get_params($input);
54
foreach (grep {$_ =~ /^mDataProp/} keys %dt_params) {
55
    $dt_params{$_} =~ s/^dt_//;
56
}
57
58
my $results;
59
# If the user filled a term, maybe it's a cardnumber.
60
# This cannot be the case if a first letter is given.
61
if ( $searchmember
62
    and not $firstletter
63
    and $searchfieldstype
64
    and $searchfieldstype eq 'standard' )
65
{
66
    my $member = Koha::Patrons->find( { cardnumber => $searchmember } );
67
    $results = {
68
        iTotalRecords        => 1,
69
        iTotalDisplayRecords => 1,
70
        patrons              => [ $member->unblessed ],
71
    } if $member;
72
}
73
74
if ($has_permission) {
75
    my ( $permission, $subpermission ) = split /\./, $has_permission;
76
    $has_permission = {permission => $permission, subpermission => $subpermission};
77
}
78
79
# Perform the patrons search
80
$results = C4::Utils::DataTables::Members::search(
81
    {
82
        searchmember => $searchmember,
83
        firstletter => $firstletter,
84
        categorycode => $categorycode,
85
        branchcode => $branchcode,
86
        searchtype => $searchtype,
87
        searchfieldstype => $searchfieldstype,
88
        dt_params => \%dt_params,
89
        ( $has_permission ? ( has_permission => $has_permission ) : () ),
90
    }
91
) unless $results;
92
93
my $prefillguarantorfields = C4::Context->preference("PrefillGuaranteeField");
94
my @prefill_fields = split(/\,/,$prefillguarantorfields);
95
96
$template->param(
97
    sEcho => $sEcho,
98
    iTotalRecords => $results->{iTotalRecords},
99
    iTotalDisplayRecords => $results->{iTotalDisplayRecords},
100
    aaData => $results->{patrons},
101
    selection_type => $selection_type,
102
    guarantor_attributes => \@prefill_fields,
103
);
104
105
output_with_http_headers $input, $cookie, $template->output, 'json';
106
107
__END__
108
109
=head1 NAME
110
111
search - a search script for finding patrons
112
113
=head1 SYNOPSIS
114
115
This script provides a service for template for patron search using DataTables
116
117
=head2 Performing a search
118
119
Call this script from a DataTables table my $searchmember = $input->param('searchmember');
120
All following params are optional:
121
    searchmember => the search terms
122
    firstletter => search patrons with surname begins with this pattern (currently only used for 1 letter)
123
    categorycode and branchcode => search patrons belong to a given categorycode or a branchcode
124
    searchtype: can be 'contain' or 'start_with'
125
    searchfieldstype: Can be 'standard', 'email', 'borrowernumber', 'userid', 'phone' or 'address'
126
127
=cut
128
129
=back
130
131
=head1 LICENSE
132
133
Copyright 2013 BibLibre
134
135
This file is part of Koha.
136
137
Koha is free software; you can redistribute it and/or modify it under the
138
terms of the GNU General Public License as published by the Free Software
139
Foundation; either version 2 of the License, or (at your option) any later
140
version.
141
142
Koha is free software; you can redistribute it and/or modify it
143
under the terms of the GNU General Public License as published by
144
the Free Software Foundation; either version 3 of the License, or
145
(at your option) any later version.
146
147
Koha is distributed in the hope that it will be useful, but
148
WITHOUT ANY WARRANTY; without even the implied warranty of
149
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
150
GNU General Public License for more details.
151
152
You should have received a copy of the GNU General Public License
153
along with Koha; if not, see <http://www.gnu.org/licenses>.

Return to bug 26597