Acquisition module has been cut into 3 files :
[koha.git] / C4 / Members.pm
1 # -*- tab-width: 8 -*-
2
3 package C4::Members;
4
5 # Copyright 2000-2003 Katipo Communications
6 #
7 # This file is part of Koha.
8 #
9 # Koha is free software; you can redistribute it and/or modify it under the
10 # terms of the GNU General Public License as published by the Free Software
11 # Foundation; either version 2 of the License, or (at your option) any later
12 # version.
13 #
14 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
15 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License along with
19 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
20 # Suite 330, Boston, MA  02111-1307 USA
21
22 # $Id$
23
24 use strict;
25 require Exporter;
26 use C4::Context;
27 use Date::Manip;
28 use C4::Date;
29 use Digest::MD5 qw(md5_base64);
30 use Date::Calc qw/Today/;
31
32 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
33
34 $VERSION = do { my @v = '$Revision$' =~ /\d+/g; shift(@v) . "." . join( "_", map { sprintf "%03d", $_ } @v ); };
35
36 =head1 NAME
37
38 C4::Members - Perl Module containing convenience functions for member handling
39
40 =head1 SYNOPSIS
41
42 use C4::Members;
43
44 =head1 DESCRIPTION
45
46 This module contains routines for adding, modifying and deleting members/patrons/borrowers 
47
48 =head1 FUNCTIONS
49
50 =over 2
51
52 =cut
53
54 #'
55
56 @ISA    = qw(Exporter);
57
58 @EXPORT = qw(
59  &BornameSearch &getmember &borrdata &borrdata2 &fixup_cardnumber &findguarantees &findguarantor &GuarantornameSearch &NewBorrowerNumber   &modmember &newmember &changepassword &borrissues &allissues
60   &checkuniquemember &getzipnamecity &getidcity &getguarantordata &getcategorytype
61   &calcexpirydate &checkuserpassword
62   &getboracctrecord
63   &borrowercategories &getborrowercategory
64   &fixEthnicity
65   &ethnicitycategories get_institutions add_member_orgs
66   &get_age &GetBorrowersFromSurname &GetBranchCodeFromBorrowers
67   &GetFlagsAndBranchFromBorrower
68 );
69
70
71 =item BornameSearch
72
73   ($count, $borrowers) = &BornameSearch($env, $searchstring, $type);
74
75 Looks up patrons (borrowers) by name.
76
77 C<$env> is ignored.
78
79 BUGFIX 499: C<$type> is now used to determine type of search.
80 if $type is "simple", search is performed on the first letter of the
81 surname only.
82
83 C<$searchstring> is a space-separated list of search terms. Each term
84 must match the beginning a borrower's surname, first name, or other
85 name.
86
87 C<&BornameSearch> returns a two-element list. C<$borrowers> is a
88 reference-to-array; each element is a reference-to-hash, whose keys
89 are the fields of the C<borrowers> table in the Koha database.
90 C<$count> is the number of elements in C<$borrowers>.
91
92 =cut
93
94 #'
95 #used by member enquiries from the intranet
96 #called by member.pl
97 sub BornameSearch {
98     my ( $env, $searchstring, $orderby, $type ) = @_;
99     my $dbh   = C4::Context->dbh;
100     my $query = "";
101     my $count;
102     my @data;
103     my @bind = ();
104
105     if ( $type eq "simple" )    # simple search for one letter only
106     {
107         $query =
108           "Select * from borrowers where surname like ? order by $orderby";
109         @bind = ("$searchstring%");
110     }
111     else    # advanced search looking in surname, firstname and othernames
112     {
113         @data  = split( ' ', $searchstring );
114         $count = @data;
115         $query = "Select * from borrowers
116                 where ((surname like ? or surname like ?
117                 or firstname  like ? or firstname like ?
118                 or othernames like ? or othernames like ?)
119                 ";
120         @bind = (
121             "$data[0]%", "% $data[0]%", "$data[0]%", "% $data[0]%",
122             "$data[0]%", "% $data[0]%"
123         );
124         for ( my $i = 1 ; $i < $count ; $i++ ) {
125             $query = $query . " and (" . " surname like ? or surname like ?
126                         or firstname  like ? or firstname like ?
127                         or othernames like ? or othernames like ?)";
128             push( @bind,
129                 "$data[$i]%",   "% $data[$i]%", "$data[$i]%",
130                 "% $data[$i]%", "$data[$i]%",   "% $data[$i]%" );
131
132             # FIXME - .= <<EOT;
133         }
134         $query = $query . ") or cardnumber like ?
135                 order by $orderby";
136         push( @bind, $searchstring );
137
138         # FIXME - .= <<EOT;
139     }
140
141     my $sth = $dbh->prepare($query);
142
143     #   warn "Q $orderby : $query";
144     $sth->execute(@bind);
145     my @results;
146     my $cnt = $sth->rows;
147     while ( my $data = $sth->fetchrow_hashref ) {
148         push( @results, $data );
149     }
150
151     #  $sth->execute;
152     $sth->finish;
153     return ( $cnt, \@results );
154 }
155
156 =item getmember
157
158   $borrower = &getmember($cardnumber, $borrowernumber);
159
160 Looks up information about a patron (borrower) by either card number
161 or borrower number. If $borrowernumber is specified, C<&borrdata>
162 searches by borrower number; otherwise, it searches by card number.
163
164 C<&getmember> returns a reference-to-hash whose keys are the fields of
165 the C<borrowers> table in the Koha database.
166
167 =cut
168
169 =head3
170
171 =over 4
172
173 ($flags, $homebranch) = GetFlagsAndBranchFromBorrower($loggedinuser);
174
175 this function read on the database to get flags and homebranch for a user
176 given on input arg.
177
178 return : 
179 it returns the $flags & the homebranch in scalar context.
180
181 =back
182
183 =cut
184
185 sub GetFlagsAndBranchFromBorrower {
186     my $loggedinuser = @_;
187     my $dbh = C4::Context->dbh;
188     my $query = "
189        SELECT flags, branchcode
190        FROM   borrowers
191        WHERE  borrowernumber = ? 
192     ";
193     my $sth = $dbh->prepare($query);
194     $sth->execute($loggedinuser);
195
196     return $sth->fetchrow;
197 }
198
199
200 #'
201 sub getmember {
202     my ( $cardnumber, $bornum ) = @_;
203     $cardnumber = uc $cardnumber;
204     my $dbh = C4::Context->dbh;
205     my $sth;
206     if ( $bornum eq '' ) {
207         $sth = $dbh->prepare("Select * from borrowers where cardnumber=?");
208         $sth->execute($cardnumber);
209     }
210     else {
211         $sth = $dbh->prepare("Select * from borrowers where borrowernumber=?");
212         $sth->execute($bornum);
213     }
214     my $data = $sth->fetchrow_hashref;
215     $sth->finish;
216     if ($data) {
217         return ($data);
218     }
219     else {    # try with firstname
220         if ($cardnumber) {
221             my $sth =
222               $dbh->prepare("select * from borrowers where firstname=?");
223             $sth->execute($cardnumber);
224             my $data = $sth->fetchrow_hashref;
225             $sth->finish;
226             return ($data);
227         }
228     }
229     return undef;
230 }
231
232 =item borrdata
233
234   $borrower = &borrdata($cardnumber, $borrowernumber);
235
236 Looks up information about a patron (borrower) by either card number
237 or borrower number. If $borrowernumber is specified, C<&borrdata>
238 searches by borrower number; otherwise, it searches by card number.
239
240 C<&borrdata> returns a reference-to-hash whose keys are the fields of
241 the C<borrowers> table in the Koha database.
242
243 =cut
244
245 #'
246 sub borrdata {
247     my ( $cardnumber, $bornum ) = @_;
248     $cardnumber = uc $cardnumber;
249     my $dbh = C4::Context->dbh;
250     my $sth;
251     if ( $bornum eq '' ) {
252         $sth =
253           $dbh->prepare(
254 "Select borrowers.*,categories.category_type from borrowers left join categories on borrowers.categorycode=categories.categorycode where cardnumber=?"
255           );
256         $sth->execute($cardnumber);
257     }
258     else {
259         $sth =
260           $dbh->prepare(
261 "Select borrowers.*,categories.category_type from borrowers left join categories on borrowers.categorycode=categories.categorycode where borrowernumber=?"
262           );
263         $sth->execute($bornum);
264     }
265     my $data = $sth->fetchrow_hashref;
266 #     warn "DATA" . $data->{category_type};
267     $sth->finish;
268     if ($data) {
269         return ($data);
270     }
271     else {    # try with firstname
272         if ($cardnumber) {
273             my $sth =
274               $dbh->prepare(
275 "Select borrowers.*,categories.category_type from borrowers left join categories on borrowers.categorycode=categories.categorycode  where firstname=?"
276               );
277             $sth->execute($cardnumber);
278             my $data = $sth->fetchrow_hashref;
279             $sth->finish;
280             return ($data);
281         }
282     }
283     return undef;
284 }
285
286 =item borrdata2
287
288   ($borrowed, $due, $fine) = &borrdata2($env, $borrowernumber);
289
290 Returns aggregate data about items borrowed by the patron with the
291 given borrowernumber.
292
293 C<$env> is ignored.
294
295 C<&borrdata2> returns a three-element array. C<$borrowed> is the
296 number of books the patron currently has borrowed. C<$due> is the
297 number of overdue items the patron currently has borrowed. C<$fine> is
298 the total fine currently due by the borrower.
299
300 =cut
301
302 #'
303 sub borrdata2 {
304     my ( $env, $bornum ) = @_;
305     my $dbh   = C4::Context->dbh;
306     my $query = "Select count(*) from issues where borrowernumber='$bornum' and
307     returndate is NULL";
308
309     # print $query;
310     my $sth = $dbh->prepare($query);
311     $sth->execute;
312     my $data = $sth->fetchrow_hashref;
313     $sth->finish;
314     $sth = $dbh->prepare(
315         "Select count(*) from issues where
316     borrowernumber='$bornum' and date_due < now() and returndate is NULL"
317     );
318     $sth->execute;
319     my $data2 = $sth->fetchrow_hashref;
320     $sth->finish;
321     $sth = $dbh->prepare(
322         "Select sum(amountoutstanding) from accountlines where
323     borrowernumber='$bornum'"
324     );
325     $sth->execute;
326     my $data3 = $sth->fetchrow_hashref;
327     $sth->finish;
328
329     return ( $data2->{'count(*)'}, $data->{'count(*)'},
330         $data3->{'sum(amountoutstanding)'} );
331 }
332
333 sub modmember {
334         my (%data) = @_;
335         my $dbh = C4::Context->dbh;
336         $data{'dateofbirth'}=format_date_in_iso($data{'dateofbirth'});
337         $data{'dateexpiry'}=format_date_in_iso($data{'dateexpiry'});
338         $data{'dateenrolled'}=format_date_in_iso($data{'dateenrolled'});
339 #       warn "num user".$data{'borrowernumber'};
340         my $query;
341         my $sth;
342         $data{'userid'}='' if ($data{'password'}eq '');
343         # test to know if u must update or not the borrower password
344         if ($data{'password'} eq '****'){
345                 
346                 $query="UPDATE borrowers SET 
347                 cardnumber  = ?,surname = ?,firstname = ?,title = ?,othernames = ?,initials = ?,
348                 streetnumber = ?,streettype = ?,address = ?,address2 = ?,city = ?,zipcode = ?,
349                 email = ?,phone = ?,mobile = ?,fax = ?,emailpro = ?,phonepro = ?,B_streetnumber = ?,
350                 B_streettype = ?,B_address = ?,B_city = ?,B_zipcode = ?,B_email = ?,B_phone = ?,dateofbirth = ?,branchcode = ?,
351                 categorycode = ?,dateenrolled = ?,dateexpiry = ?,gonenoaddress = ?,lost = ?,debarred = ?,contactname = ?,
352                 contactfirstname = ?,contacttitle = ?,guarantorid = ?,borrowernotes = ?,relationship =  ?,ethnicity = ?,
353                 ethnotes = ?,sex = ?,flags = ?,userid = ?,opacnote = ?,contactnote = ?,sort1 = ?,sort2 = ? 
354                 WHERE borrowernumber=$data{'borrowernumber'}";
355         $sth=$dbh->prepare($query);
356         $sth->execute(
357                 $data{'cardnumber'},$data{'surname'},
358                 $data{'firstname'},$data{'title'},
359                 $data{'othernames'},$data{'initials'},
360                 $data{'streetnumber'},$data{'streettype'},
361                 $data{'address'},$data{'address2'},
362                 $data{'city'},$data{'zipcode'},
363                 $data{'email'},$data{'phone'},
364                 $data{'mobile'},$data{'fax'},
365                 $data{'emailpro'},$data{'phonepro'},
366                 $data{'B_streetnumber'},$data{'B_streettype'},
367                 $data{'B_address'},$data{'B_city'},
368                 $data{'B_zipcode'},$data{'B_email'},$data{'B_phone'},
369                 $data{'dateofbirth'},$data{'branchcode'},
370                 $data{'categorycode'},$data{'dateenrolled'},
371                 $data{'dateexpiry'},$data{'gonenoaddress'},
372                 $data{'lost'},$data{'debarred'},
373                 $data{'contactname'},$data{'contactfirstname'},
374                 $data{'contacttitle'},$data{'guarantorid'},
375                 $data{'borrowernotes'},$data{'relationship'},
376                 $data{'ethnicity'},$data{'ethnotes'},
377                 $data{'sex'},
378                 $data{'flags'},$data{'userid'},
379                 $data{'opacnote'},$data{'contactnote'},
380                 $data{'sort1'},$data{'sort2'});
381         }
382         else{
383                 
384                 ($data{'password'}=md5_base64($data{'password'})) if ($data{'password'} ne '');
385                 $query="UPDATE borrowers SET 
386                 cardnumber  = ?,surname = ?,firstname = ?,title = ?,othernames = ?,initials = ?,
387                 streetnumber = ?,streettype = ?,address = ?,address2 = ?,city = ?,zipcode = ?,
388                 email = ?,phone = ?,mobile = ?,fax = ?,emailpro = ?,phonepro = ?,B_streetnumber = ?,
389                 B_streettype = ?,B_address = ?,B_city = ?,B_zipcode = ?,B_email = ?,B_phone = ?,dateofbirth = ?,branchcode = ?,
390                 categorycode = ?,dateenrolled = ?,dateexpiry = ?,gonenoaddress = ?,lost = ?,debarred = ?,contactname = ?,
391                 contactfirstname = ?,contacttitle = ?,guarantorid = ?,borrowernotes = ?,relationship =  ?,ethnicity = ?,
392                 ethnotes = ?,sex = ?,password = ?,flags = ?,userid = ?,opacnote = ?,contactnote = ?,sort1 = ?,sort2 = ? 
393                 WHERE borrowernumber=$data{'borrowernumber'}";
394         $sth=$dbh->prepare($query);
395         $sth->execute(
396                 $data{'cardnumber'},$data{'surname'},
397                 $data{'firstname'},$data{'title'},
398                 $data{'othernames'},$data{'initials'},
399                 $data{'streetnumber'},$data{'streettype'},
400                 $data{'address'},$data{'address2'},
401                 $data{'city'},$data{'zipcode'},
402                 $data{'email'},$data{'phone'},
403                 $data{'mobile'},$data{'fax'},
404                 $data{'emailpro'},$data{'phonepro'},
405                 $data{'B_streetnumber'},$data{'B_streettype'},
406                 $data{'B_address'},$data{'B_city'},
407                 $data{'B_zipcode'},$data{'B_email'},$data{'B_phone'},
408                 $data{'dateofbirth'},$data{'branchcode'},
409                 $data{'categorycode'},$data{'dateenrolled'},
410                 $data{'dateexpiry'},$data{'gonenoaddress'},
411                 $data{'lost'},$data{'debarred'},
412                 $data{'contactname'},$data{'contactfirstname'},
413                 $data{'contacttitle'},$data{'guarantorid'},
414                 $data{'borrowernotes'},$data{'relationship'},
415                 $data{'ethnicity'},$data{'ethnotes'},
416                 $data{'sex'},$data{'password'},
417                 $data{'flags'},$data{'userid'},
418                 $data{'opacnote'},$data{'contactnote'},
419                 $data{'sort1'},$data{'sort2'}
420                 );
421         }
422         $sth->finish;
423         # ok if its an adult (type) it may have borrowers that depend on it as a guarantor
424         # so when we update information for an adult we should check for guarantees and update the relevant part
425         # of their records, ie addresses and phone numbers
426         my ($category_type,undef)=getcategorytype($data{'category_type'});
427         if ($category_type eq 'A' ){
428         
429         # is adult check guarantees;
430                 updateguarantees(%data);
431         
432         }
433
434
435 }
436
437 sub newmember {
438     my (%data) = @_;
439     my $dbh = C4::Context->dbh;
440     $data{'userid'} = '' unless $data{'password'};
441     $data{'password'} = md5_base64( $data{'password'} ) if $data{'password'};
442     $data{'dateofbirth'} = format_date_in_iso( $data{'dateofbirth'} );
443     $data{'dateenrolled'} = format_date_in_iso( $data{'dateenrolled'} );
444     $data{'dateexpiry'} = format_date_in_iso( $data{'dateexpiry'} );
445         my $query =
446         "insert into borrowers set cardnumber="
447       . $dbh->quote( $data{'cardnumber'} )
448       . ",surname="
449       . $dbh->quote( $data{'surname'} )
450       . ",firstname="
451       . $dbh->quote( $data{'firstname'} )
452       . ",title="
453       . $dbh->quote( $data{'title'} )
454       . ",othernames="
455       . $dbh->quote( $data{'othernames'} )
456       . ",initials="
457       . $dbh->quote( $data{'initials'} )
458       . ",streetnumber="
459       . $dbh->quote( $data{'streetnumber'} )
460       . ",streettype="
461       . $dbh->quote( $data{'streettype'} )
462       . ",address="
463       . $dbh->quote( $data{'address'} )
464       . ",address2="
465       . $dbh->quote( $data{'address2'} )
466       . ",zipcode="
467       . $dbh->quote( $data{'zipcode'} )
468       . ",city="
469       . $dbh->quote( $data{'city'} )
470       . ",phone="
471       . $dbh->quote( $data{'phone'} )
472       . ",email="
473       . $dbh->quote( $data{'email'} )
474       . ",mobile="
475       . $dbh->quote( $data{'mobile'} )
476       . ",phonepro="
477       . $dbh->quote( $data{'phonepro'} )
478       . ",opacnote="
479       . $dbh->quote( $data{'opacnote'} )
480       . ",guarantorid="
481       . $dbh->quote( $data{'guarantorid'} )
482       . ",dateofbirth="
483       . $dbh->quote( $data{'dateofbirth'} )
484       . ",branchcode="
485       . $dbh->quote( $data{'branchcode'} )
486       . ",categorycode="
487       . $dbh->quote( $data{'categorycode'} )
488       . ",dateenrolled="
489       . $dbh->quote( $data{'dateenrolled'} )
490       . ",contactname="
491       . $dbh->quote( $data{'contactname'} )
492       . ",borrowernotes="
493       . $dbh->quote( $data{'borrowernotes'} )
494       . ",dateexpiry="
495       . $dbh->quote( $data{'dateexpiry'} )
496       . ",contactnote="
497       . $dbh->quote( $data{'contactnote'} )
498       . ",B_address="
499       . $dbh->quote( $data{'B_address'} )
500       . ",B_zipcode="
501       . $dbh->quote( $data{'B_zipcode'} )
502       . ",B_city="
503       . $dbh->quote( $data{'B_city'} )
504       . ",B_phone="
505       . $dbh->quote( $data{'B_phone'} )
506       . ",B_email="
507       . $dbh->quote( $data{'B_email'}, )
508       . ",password="
509       . $dbh->quote( $data{'password'} )
510       . ",userid="
511       . $dbh->quote( $data{'userid'} )
512       . ",sort1="
513       . $dbh->quote( $data{'sort1'} )
514       . ",sort2="
515       . $dbh->quote( $data{'sort2'} )
516       . ",contacttitle="
517       . $dbh->quote( $data{'contacttitle'} )
518       . ",emailpro="
519       . $dbh->quote( $data{'emailpro'} )
520       . ",contactfirstname="
521       . $dbh->quote( $data{'contactfirstname'} ) 
522       . ",sex="
523       . $dbh->quote( $data{'sex'} ) 
524       . ",fax="
525       . $dbh->quote( $data{'fax'} )
526       . ",flags="
527       . $dbh->quote( $data{'flags'} )
528       . ",relationship="
529       . $dbh->quote( $data{'relationship'} )
530       . ",B_streetnumber="
531       . $dbh->quote( $data{'B_streetnumber'}) 
532       . ",B_streettype="
533       . $dbh->quote( $data{'B_streettype'})
534       . ",gonenoaddress="
535       . $dbh->quote( $data{'gonenoaddress'})    
536       . ",lost="
537       . $dbh->quote( $data{'lost'})                     
538       . ",debarred="
539       . $dbh->quote( $data{'debarred'})
540       . ",ethnicity="
541       . $dbh->quote( $data{'ethnicity'})
542       . ",ethnotes="
543       . $dbh->quote( $data{'ethnotes'});
544
545     my $sth = $dbh->prepare($query);
546     $sth->execute;
547     $sth->finish;
548     $data{'borrowernumber'} = $dbh->{'mysql_insertid'};
549     return $data{'borrowernumber'};
550 }
551
552 sub changepassword {
553     my ( $uid, $member, $digest ) = @_;
554     my $dbh = C4::Context->dbh;
555
556 #Make sure the userid chosen is unique and not theirs if non-empty. If it is not,
557 #Then we need to tell the user and have them create a new one.
558     my $sth =
559       $dbh->prepare(
560         "select * from borrowers where userid=? and borrowernumber != ?");
561     $sth->execute( $uid, $member );
562     if ( ( $uid ne '' ) && ( $sth->fetchrow ) ) {
563         return 0;
564     }
565     else {
566
567         #Everything is good so we can update the information.
568         $sth =
569           $dbh->prepare(
570             "update borrowers set userid=?, password=? where borrowernumber=?");
571         $sth->execute( $uid, $digest, $member );
572         return 1;
573     }
574 }
575
576 sub getmemberfromuserid {
577     my ($userid) = @_;
578     my $dbh      = C4::Context->dbh;
579     my $sth      = $dbh->prepare("select * from borrowers where userid=?");
580     $sth->execute($userid);
581     return $sth->fetchrow_hashref;
582 }
583
584 sub updateguarantees {
585     my (%data) = @_;
586     my $dbh = C4::Context->dbh;
587     my ( $count, $guarantees ) = findguarantees( $data{'borrowernumber'} );
588     for ( my $i = 0 ; $i < $count ; $i++ ) {
589
590         # FIXME
591         # It looks like the $i is only being returned to handle walking through
592         # the array, which is probably better done as a foreach loop.
593         #
594         my $guaquery =
595 "update borrowers set streetaddress='$data{'address'}',faxnumber='$data{'faxnumber'}',
596                 streetcity='$data{'streetcity'}',phoneday='$data{'phoneday'}',city='$data{'city'}',area='$data{'area'}',phone='$data{'phone'}'
597                 ,streetaddress='$data{'address'}'
598                 where borrowernumber='$guarantees->[$i]->{'borrowernumber'}'";
599         my $sth3 = $dbh->prepare($guaquery);
600         $sth3->execute;
601         $sth3->finish;
602     }
603 }
604 ################################################################################
605
606 =item fixup_cardnumber
607
608 Warning: The caller is responsible for locking the members table in write
609 mode, to avoid database corruption.
610
611 =cut
612
613 use vars qw( @weightings );
614 my @weightings = ( 8, 4, 6, 3, 5, 2, 1 );
615
616 sub fixup_cardnumber ($) {
617     my ($cardnumber) = @_;
618     my $autonumber_members = C4::Context->boolean_preference('autoMemberNum');
619     $autonumber_members = 0 unless defined $autonumber_members;
620
621     # Find out whether member numbers should be generated
622     # automatically. Should be either "1" or something else.
623     # Defaults to "0", which is interpreted as "no".
624
625     #     if ($cardnumber !~ /\S/ && $autonumber_members) {
626     if ($autonumber_members) {
627         my $dbh = C4::Context->dbh;
628         if ( C4::Context->preference('checkdigit') eq 'katipo' ) {
629
630             # if checkdigit is selected, calculate katipo-style cardnumber.
631             # otherwise, just use the max()
632             # purpose: generate checksum'd member numbers.
633             # We'll assume we just got the max value of digits 2-8 of member #'s
634             # from the database and our job is to increment that by one,
635             # determine the 1st and 9th digits and return the full string.
636             my $sth =
637               $dbh->prepare(
638                 "select max(substring(borrowers.cardnumber,2,7)) from borrowers"
639               );
640             $sth->execute;
641
642             my $data = $sth->fetchrow_hashref;
643             $cardnumber = $data->{'max(substring(borrowers.cardnumber,2,7))'};
644             $sth->finish;
645             if ( !$cardnumber ) {    # If DB has no values,
646                 $cardnumber = 1000000;    # start at 1000000
647             }
648             else {
649                 $cardnumber += 1;
650             }
651
652             my $sum = 0;
653             for ( my $i = 0 ; $i < 8 ; $i += 1 ) {
654
655                 # read weightings, left to right, 1 char at a time
656                 my $temp1 = $weightings[$i];
657
658                 # sequence left to right, 1 char at a time
659                 my $temp2 = substr( $cardnumber, $i, 1 );
660
661                 # mult each char 1-7 by its corresponding weighting
662                 $sum += $temp1 * $temp2;
663             }
664
665             my $rem = ( $sum % 11 );
666             $rem = 'X' if $rem == 10;
667
668             $cardnumber = "V$cardnumber$rem";
669         }
670         else {
671
672      # MODIFIED BY JF: mysql4.1 allows casting as an integer, which is probably
673      # better. I'll leave the original in in case it needs to be changed for you
674             my $sth =
675               $dbh->prepare(
676                 "select max(cast(cardnumber as signed)) from borrowers");
677
678       #my $sth=$dbh->prepare("select max(borrowers.cardnumber) from borrowers");
679
680             $sth->execute;
681
682             my ($result) = $sth->fetchrow;
683             $sth->finish;
684             $cardnumber = $result + 1;
685         }
686     }
687     return $cardnumber;
688 }
689
690 sub findguarantees {
691     my ($bornum) = @_;
692     my $dbh      = C4::Context->dbh;
693     my $sth      = $dbh->prepare(
694         "select cardnumber,borrowernumber from borrowers where
695   guarantorid=?"
696     );
697     $sth->execute($bornum);
698     my @dat;
699     my $i = 0;
700     while ( my $data = $sth->fetchrow_hashref ) {
701         $dat[$i] = $data;
702         $i++;
703     }
704     $sth->finish;
705     return ( $i, \@dat );
706 }
707
708 =item findguarantor
709
710   $guarantor = &findguarantor($borrower_no);
711   $guarantor_cardno = $guarantor->{"cardnumber"};
712   $guarantor_surname = $guarantor->{"surname"};
713   ...
714
715 C<&findguarantor> takes a borrower number (presumably that of a child
716 patron), finds the guarantor for C<$borrower_no> (the child's parent),
717 and returns the record for the guarantor.
718
719 C<&findguarantor> returns a reference-to-hash. Its keys are the fields
720 from the C<borrowers> database table;
721
722 =cut
723
724 #'
725 sub findguarantor {
726     my ($bornum) = @_;
727     my $dbh = C4::Context->dbh;
728     my $sth = $dbh->prepare("Select * from borrowers where borrowernumber=?");
729     $sth->execute($bornum);
730     my $data = $sth->fetchrow_hashref;
731     $sth->finish;
732     return ($data);
733 }
734
735 =item GuarantornameSearch
736
737   ($count, $borrowers) = &GuarantornameSearch($env, $searchstring, $type);
738
739 Looks up guarantor  by name.
740
741 C<$env> is ignored.
742
743 BUGFIX 499: C<$type> is now used to determine type of search.
744 if $type is "simple", search is performed on the first letter of the
745 surname only.
746
747 C<$searchstring> is a space-separated list of search terms. Each term
748 must match the beginning a borrower's surname, first name, or other
749 name.
750
751 C<&GuarantornameSearch> returns a two-element list. C<$borrowers> is a
752 reference-to-array; each element is a reference-to-hash, whose keys
753 are the fields of the C<borrowers> table in the Koha database.
754 C<$count> is the number of elements in C<$borrowers>.
755
756 return all info from guarantor =>only category_type A
757
758 =cut
759
760 #'
761 #used by member enquiries from the intranet
762 #called by guarantor_search.pl
763 sub GuarantornameSearch {
764     my ( $env, $searchstring, $orderby, $type ) = @_;
765     my $dbh   = C4::Context->dbh;
766     my $query = "";
767     my $count;
768     my @data;
769     my @bind = ();
770
771     if ( $type eq "simple" )    # simple search for one letter only
772     {
773         $query =
774 "Select * from borrowers,categories  where borrowers.categorycode=categories.categorycode and category_type='A'  and  surname like ? order by $orderby";
775         @bind = ("$searchstring%");
776     }
777     else    # advanced search looking in surname, firstname and othernames
778     {
779         @data  = split( ' ', $searchstring );
780         $count = @data;
781         $query = "Select * from borrowers,categories
782                 where ((surname like ? or surname like ?
783                 or firstname  like ? or firstname like ?
784                 or othernames like ? or othernames like ?) and borrowers.categorycode=categories.categorycode and category_type='A' 
785                 ";
786         @bind = (
787             "$data[0]%", "% $data[0]%", "$data[0]%", "% $data[0]%",
788             "$data[0]%", "% $data[0]%"
789         );
790         for ( my $i = 1 ; $i < $count ; $i++ ) {
791             $query = $query . " and (" . " surname like ? or surname like ?
792                         or firstname  like ? or firstname like ?
793                         or othernames like ? or othernames like ?)";
794             push( @bind,
795                 "$data[$i]%",   "% $data[$i]%", "$data[$i]%",
796                 "% $data[$i]%", "$data[$i]%",   "% $data[$i]%" );
797
798             # FIXME - .= <<EOT;
799         }
800         $query = $query . ") or cardnumber like ?
801                 order by $orderby";
802         push( @bind, $searchstring );
803
804         # FIXME - .= <<EOT;
805     }
806
807     my $sth = $dbh->prepare($query);
808     $sth->execute(@bind);
809     my @results;
810     my $cnt = $sth->rows;
811     while ( my $data = $sth->fetchrow_hashref ) {
812         push( @results, $data );
813     }
814
815     #  $sth->execute;
816     $sth->finish;
817     return ( $cnt, \@results );
818 }
819
820 =item NewBorrowerNumber
821
822   $num = &NewBorrowerNumber();
823
824 Allocates a new, unused borrower number, and returns it.
825
826 =cut
827
828 #'
829 # FIXME - This is identical to C4::Circulation::Borrower::NewBorrowerNumber.
830 # Pick one and stick with it. Preferably use the other one. This function
831 # doesn't belong in C4::Search.
832 sub NewBorrowerNumber {
833     my $dbh = C4::Context->dbh;
834     my $sth = $dbh->prepare("Select max(borrowernumber) from borrowers");
835     $sth->execute;
836     my $data = $sth->fetchrow_hashref;
837     $sth->finish;
838     $data->{'max(borrowernumber)'}++;
839     return ( $data->{'max(borrowernumber)'} );
840 }
841
842 =head2 borrissues
843
844   ($count, $issues) = &borrissues($borrowernumber);
845
846 Looks up what the patron with the given borrowernumber has borrowed.
847
848 C<&borrissues> returns a two-element array. C<$issues> is a
849 reference-to-array, where each element is a reference-to-hash; the
850 keys are the fields from the C<issues>, C<biblio>, and C<items> tables
851 in the Koha database. C<$count> is the number of elements in
852 C<$issues>.
853
854 =cut
855
856 #'
857 sub borrissues {
858     my ($bornum) = @_;
859     my $dbh      = C4::Context->dbh;
860     my $sth      = $dbh->prepare(
861         "Select * from issues,biblio,items where borrowernumber=?
862    and items.itemnumber=issues.itemnumber
863         and items.biblionumber=biblio.biblionumber
864         and issues.returndate is NULL order by date_due"
865     );
866     $sth->execute($bornum);
867     my @result;
868     while ( my $data = $sth->fetchrow_hashref ) {
869         push @result, $data;
870     }
871     $sth->finish;
872     return ( scalar(@result), \@result );
873 }
874
875 =head2 allissues
876
877   ($count, $issues) = &allissues($borrowernumber, $sortkey, $limit);
878
879 Looks up what the patron with the given borrowernumber has borrowed,
880 and sorts the results.
881
882 C<$sortkey> is the name of a field on which to sort the results. This
883 should be the name of a field in the C<issues>, C<biblio>,
884 C<biblioitems>, or C<items> table in the Koha database.
885
886 C<$limit> is the maximum number of results to return.
887
888 C<&allissues> returns a two-element array. C<$issues> is a
889 reference-to-array, where each element is a reference-to-hash; the
890 keys are the fields from the C<issues>, C<biblio>, C<biblioitems>, and
891 C<items> tables of the Koha database. C<$count> is the number of
892 elements in C<$issues>
893
894 =cut
895
896 #'
897 sub allissues {
898     my ( $bornum, $order, $limit ) = @_;
899
900     #FIXME: sanity-check order and limit
901     my $dbh   = C4::Context->dbh;
902     my $count=0;
903     my $query = "Select * from issues,biblio,items,biblioitems
904   where borrowernumber=? and
905   items.biblioitemnumber=biblioitems.biblioitemnumber and
906   items.itemnumber=issues.itemnumber and
907   items.biblionumber=biblio.biblionumber order by $order";
908     if ( $limit != 0 ) {
909         $query .= " limit $limit";
910     }
911
912     #print $query;
913     my $sth = $dbh->prepare($query);
914     $sth->execute($bornum);
915     my @result;
916     my $i = 0;
917     while ( my $data = $sth->fetchrow_hashref ) {
918         $result[$i] = $data;
919         $i++;
920         $count++;
921     }
922
923     # get all issued items for bornum from oldissues table
924     # large chunk of older issues data put into table oldissues
925     # to speed up db calls for issuing items
926     if(C4::Context->preference("ReadingHistory")){
927           my $query2="SELECT * FROM oldissues,biblio,items,biblioitems
928                       WHERE borrowernumber=? 
929                       AND items.biblioitemnumber=biblioitems.biblioitemnumber
930                       AND items.itemnumber=oldissues.itemnumber
931                       AND items.biblionumber=biblio.biblionumber
932                       ORDER BY $order";
933           if ($limit !=0){
934                 $limit=$limit-$count;
935                 $query2.=" limit $limit";
936           }
937
938           my $sth2=$dbh->prepare($query2);
939           $sth2->execute($bornum);
940
941           while (my $data2=$sth2->fetchrow_hashref){
942                 $result[$i]=$data2;
943                 $i++;
944           }
945           $sth2->finish;
946     }
947     $sth->finish;
948
949     return ( $i, \@result );
950 }
951
952 =head2 getboracctrecord
953
954   ($count, $acctlines, $total) = &getboracctrecord($env, $borrowernumber);
955
956 Looks up accounting data for the patron with the given borrowernumber.
957
958 C<$env> is ignored.
959
960 (FIXME - I'm not at all sure what this is about.)
961
962 C<&getboracctrecord> returns a three-element array. C<$acctlines> is a
963 reference-to-array, where each element is a reference-to-hash; the
964 keys are the fields of the C<accountlines> table in the Koha database.
965 C<$count> is the number of elements in C<$acctlines>. C<$total> is the
966 total amount outstanding for all of the account lines.
967
968 =cut
969
970 #'
971 sub getboracctrecord {
972     my ( $env, $params ) = @_;
973     my $dbh = C4::Context->dbh;
974     my @acctlines;
975     my $numlines = 0;
976     my $sth      = $dbh->prepare(
977         "Select * from accountlines where
978 borrowernumber=? order by date desc,timestamp desc"
979     );
980
981     #   print $query;
982     $sth->execute( $params->{'borrowernumber'} );
983     my $total = 0;
984     while ( my $data = $sth->fetchrow_hashref ) {
985
986         #FIXME before reinstating: insecure?
987         #      if ($data->{'itemnumber'} ne ''){
988         #        $query="Select * from items,biblio where items.itemnumber=
989         #       '$data->{'itemnumber'}' and biblio.biblionumber=items.biblionumber";
990         #       my $sth2=$dbh->prepare($query);
991         #       $sth2->execute;
992         #       my $data2=$sth2->fetchrow_hashref;
993         #       $sth2->finish;
994         #       $data=$data2;
995         #     }
996         $acctlines[$numlines] = $data;
997         $numlines++;
998         $total += $data->{'amountoutstanding'};
999     }
1000     $sth->finish;
1001     return ( $numlines, \@acctlines, $total );
1002 }
1003
1004 =head2 checkuniquemember (OUEST-PROVENCE)
1005
1006   $result = &checkuniquemember($collectivity,$surname,$categorycode,$firstname,$dateofbirth);
1007
1008 Checks that a member exists or not in the database.
1009
1010 C<&result> is 1 (=exist) or 0 (=does not exist)
1011 C<&collectivity> is 1 (= we add a collectivity) or 0 (= we add a physical member)
1012 C<&surname> is the surname
1013 C<&categorycode> is from categorycode table
1014 C<&firstname> is the firstname (only if collectivity=0)
1015 C<&dateofbirth> is the date of birth (only if collectivity=0)
1016
1017 =cut
1018
1019 sub checkuniquemember {
1020     my ( $collectivity, $surname, $firstname, $dateofbirth ) = @_;
1021     my $dbh = C4::Context->dbh;
1022     my $request;
1023     if ($collectivity) {
1024
1025 #                               $request="select count(*) from borrowers where surname=? and categorycode=?";
1026         $request =
1027           "select borrowernumber,categorycode from borrowers where surname=? ";
1028     }
1029     else {
1030
1031 #                               $request="select count(*) from borrowers where surname=? and categorycode=? and firstname=? and dateofbirth=?";
1032         $request =
1033 "select borrowernumber,categorycode from borrowers where surname=?  and firstname=? and dateofbirth=?";
1034     }
1035     my $sth = $dbh->prepare($request);
1036     if ($collectivity) {
1037         $sth->execute( uc($surname) );
1038     }
1039     else {
1040         $sth->execute( uc($surname), ucfirst($firstname), $dateofbirth );
1041     }
1042     my @data = $sth->fetchrow;
1043     if ( $data[0] ) {
1044         $sth->finish;
1045         return $data[0], $data[1];
1046
1047         #
1048     }
1049     else {
1050         $sth->finish;
1051         return 0;
1052     }
1053 }
1054
1055 =head2 getzipnamecity (OUEST-PROVENCE)
1056
1057 take all info from table city for the fields city and  zip
1058 check for the name and the zip code of the city selected
1059
1060 =cut
1061
1062 sub getzipnamecity {
1063     my ($cityid) = @_;
1064     my $dbh      = C4::Context->dbh;
1065     my $sth      =
1066       $dbh->prepare(
1067         "select city_name,city_zipcode from cities where cityid=? ");
1068     $sth->execute($cityid);
1069     my @data = $sth->fetchrow;
1070     return $data[0], $data[1];
1071 }
1072
1073 =head2 updatechildguarantor (OUEST-PROVENCE)
1074
1075 check for title,firstname,surname,adress,zip code and city  from guarantor to 
1076 guarantorchild
1077
1078 =cut
1079
1080 #'
1081
1082 sub getguarantordata {
1083     my ($borrowerid) = @_;
1084     my $dbh          = C4::Context->dbh;
1085     my $sth          =
1086       $dbh->prepare(
1087 "Select title,firstname,surname,streetnumber,address,streettype,address2,zipcode,city,phone,phonepro,mobile,email,emailpro,fax  from borrowers where borrowernumber =? "
1088       );
1089     $sth->execute($borrowerid);
1090     my $guarantor_data = $sth->fetchrow_hashref;
1091     $sth->finish;
1092     return $guarantor_data;
1093 }
1094
1095 =head2 getdcity (OUEST-PROVENCE)
1096 recover cityid  with city_name condition
1097 =cut
1098
1099 sub getidcity {
1100     my ($city_name) = @_;
1101     my $dbh = C4::Context->dbh;
1102     my $sth = $dbh->prepare("select cityid from cities where city_name=? ");
1103     $sth->execute($city_name);
1104     my $data = $sth->fetchrow;
1105     return $data;
1106 }
1107
1108 =head2 getcategorytype (OUEST-PROVENCE)
1109
1110 check for the category_type with categorycode
1111 and return the category_type 
1112
1113 =cut
1114
1115 sub getcategorytype {
1116     my ($categorycode) = @_;
1117     my $dbh            = C4::Context->dbh;
1118     my $sth            =
1119       $dbh->prepare(
1120 "Select category_type,description from categories where categorycode=?  "
1121       );
1122     $sth->execute($categorycode);
1123     my ( $category_type, $description ) = $sth->fetchrow;
1124     return $category_type, $description;
1125 }
1126
1127 sub calcexpirydate {
1128     my ( $categorycode, $dateenrolled ) = @_;
1129     my $dbh = C4::Context->dbh;
1130     my $sth =
1131       $dbh->prepare(
1132         "select enrolmentperiod from categories where categorycode=?");
1133     $sth->execute($categorycode);
1134     my ($enrolmentperiod) = $sth->fetchrow;
1135     $enrolmentperiod = 12 unless ($enrolmentperiod);
1136     return format_date_in_iso(
1137         &DateCalc( $dateenrolled, "$enrolmentperiod months" ) );
1138 }
1139
1140 =head2 checkuserpassword (OUEST-PROVENCE)
1141
1142 check for the password and login are not used
1143 return the number of record 
1144 0=> NOT USED 1=> USED
1145
1146 =cut
1147
1148 sub checkuserpassword {
1149     my ( $borrowernumber, $userid, $password ) = @_;
1150     $password = md5_base64($password);
1151     my $dbh = C4::Context->dbh;
1152     my $sth =
1153       $dbh->prepare(
1154 "Select count(*) from borrowers where borrowernumber !=? and userid =? and password=? "
1155       );
1156     $sth->execute( $borrowernumber, $userid, $password );
1157     my $number_rows = $sth->fetchrow;
1158     return $number_rows;
1159
1160 }
1161
1162 =head2 borrowercategories
1163
1164   ($codes_arrayref, $labels_hashref) = &borrowercategories();
1165
1166 Looks up the different types of borrowers in the database. Returns two
1167 elements: a reference-to-array, which lists the borrower category
1168 codes, and a reference-to-hash, which maps the borrower category codes
1169 to category descriptions.
1170
1171 =cut
1172
1173 #'
1174 sub borrowercategories {
1175     my ( $category_type, $action ) = @_;
1176     my $dbh = C4::Context->dbh;
1177     my $request;
1178     $request =
1179 "Select categorycode,description from categories where category_type=? order by categorycode";
1180     my $sth = $dbh->prepare($request);
1181     $sth->execute($category_type);
1182     my %labels;
1183     my @codes;
1184
1185     while ( my $data = $sth->fetchrow_hashref ) {
1186         push @codes, $data->{'categorycode'};
1187         $labels{ $data->{'categorycode'} } = $data->{'description'};
1188     }
1189     $sth->finish;
1190     return ( \@codes, \%labels );
1191 }
1192
1193 =head2 getborrowercategory
1194
1195   $description,$dateofbirthrequired,$upperagelimit,$category_type = &getborrowercategory($categorycode);
1196
1197 Given the borrower's category code, the function returns the corresponding
1198 description , dateofbirthrequired , upperagelimit and category type for a comprehensive information display.
1199
1200 =cut
1201
1202 sub getborrowercategory {
1203     my ($catcode) = @_;
1204     my $dbh       = C4::Context->dbh;
1205     my $sth       =
1206       $dbh->prepare(
1207         "SELECT description,dateofbirthrequired,upperagelimit,category_type FROM categories WHERE categorycode = ?");
1208     $sth->execute($catcode);
1209     my ($description,$dateofbirthrequired,$upperagelimit,$category_type) = $sth->fetchrow();
1210     $sth->finish();
1211     return ($description,$dateofbirthrequired,$upperagelimit,$category_type);
1212 }    # sub getborrowercategory
1213
1214
1215
1216 =head2 ethnicitycategories
1217
1218   ($codes_arrayref, $labels_hashref) = &ethnicitycategories();
1219
1220 Looks up the different ethnic types in the database. Returns two
1221 elements: a reference-to-array, which lists the ethnicity codes, and a
1222 reference-to-hash, which maps the ethnicity codes to ethnicity
1223 descriptions.
1224
1225 =cut
1226
1227 #'
1228
1229 sub ethnicitycategories {
1230     my $dbh = C4::Context->dbh;
1231     my $sth = $dbh->prepare("Select code,name from ethnicity order by name");
1232     $sth->execute;
1233     my %labels;
1234     my @codes;
1235     while ( my $data = $sth->fetchrow_hashref ) {
1236         push @codes, $data->{'code'};
1237         $labels{ $data->{'code'} } = $data->{'name'};
1238     }
1239     $sth->finish;
1240     return ( \@codes, \%labels );
1241 }
1242
1243 =head2 fixEthnicity
1244
1245   $ethn_name = &fixEthnicity($ethn_code);
1246
1247 Takes an ethnicity code (e.g., "european" or "pi") and returns the
1248 corresponding descriptive name from the C<ethnicity> table in the
1249 Koha database ("European" or "Pacific Islander").
1250
1251 =cut
1252
1253 #'
1254
1255 sub fixEthnicity($) {
1256
1257     my $ethnicity = shift;
1258     my $dbh       = C4::Context->dbh;
1259     my $sth       = $dbh->prepare("Select name from ethnicity where code = ?");
1260     $sth->execute($ethnicity);
1261     my $data = $sth->fetchrow_hashref;
1262     $sth->finish;
1263     return $data->{'name'};
1264 }    # sub fixEthnicity
1265
1266
1267
1268 =head2 get_age
1269
1270   $dateofbirth,$date = &get_age($date);
1271
1272 this function return the borrowers age with the value of dateofbirth
1273
1274 =cut
1275 #'
1276 sub get_age {
1277     my ($date, $date_ref) = @_;
1278
1279     if (not defined $date_ref) {
1280         $date_ref = sprintf('%04d-%02d-%02d', Today());
1281     }
1282
1283     my ($year1, $month1, $day1) = split /-/, $date;
1284     my ($year2, $month2, $day2) = split /-/, $date_ref;
1285
1286     my $age = $year2 - $year1;
1287     if ($month1.$day1 > $month2.$day2) {
1288         $age--;
1289     }
1290
1291     return $age;
1292 }# sub get_age
1293
1294
1295
1296 =head2 get_institutions
1297   $insitutions = get_institutions();
1298
1299 Just returns a list of all the borrowers of type I, borrownumber and name
1300 =cut
1301
1302 #'
1303 sub get_institutions {
1304     my $dbh = C4::Context->dbh();
1305     my $sth =
1306       $dbh->prepare(
1307 "SELECT borrowernumber,surname FROM borrowers WHERE categorycode=? ORDER BY surname"
1308       );
1309     $sth->execute('I');
1310     my %orgs;
1311     while ( my $data = $sth->fetchrow_hashref() ) {
1312         $orgs{ $data->{'borrowernumber'} } = $data;
1313     }
1314     $sth->finish();
1315     return ( \%orgs );
1316
1317 }    # sub get_institutions
1318
1319 =head2 add_member_orgs
1320
1321   add_member_orgs($borrowernumber,$borrowernumbers);
1322
1323 Takes a borrowernumber and a list of other borrowernumbers and inserts them into the borrowers_to_borrowers table
1324
1325 =cut
1326
1327 #'
1328 sub add_member_orgs {
1329     my ( $borrowernumber, $otherborrowers ) = @_;
1330     my $dbh   = C4::Context->dbh();
1331     my $query =
1332       "INSERT INTO borrowers_to_borrowers (borrower1,borrower2) VALUES (?,?)";
1333     my $sth = $dbh->prepare($query);
1334     foreach my $bornum (@$otherborrowers) {
1335         $sth->execute( $borrowernumber, $bornum );
1336     }
1337     $sth->finish();
1338
1339 }    # sub add_member_orgs
1340
1341 =head2 GetBorrowersFromSurname
1342
1343 =over 4
1344
1345 \@resutlts = GetBorrowersFromSurname($surname)
1346 this function get the list of borrower names like $surname.
1347 return :
1348 the table of results in @results
1349
1350 =back
1351
1352 =cut
1353 sub GetBorrowersFromSurname  {
1354     my ($searchstring)=@_;
1355     my $dbh = C4::Context->dbh;
1356     $searchstring=~ s/\'/\\\'/g;
1357     my @data=split(' ',$searchstring);
1358     my $count=@data;
1359     my $query = qq|
1360         SELECT   surname,firstname
1361         FROM     borrowers
1362         WHERE    (surname like ?)
1363         ORDER BY surname
1364     |;
1365     my $sth=$dbh->prepare($query);
1366     $sth->execute("$data[0]%");
1367     my @results;
1368     my $count = 0;
1369     while (my $data=$sth->fetchrow_hashref){
1370          push(@results,$data);
1371          $count++;
1372     }
1373      $sth->finish;
1374      return ($count,\@results);
1375 }
1376
1377 =head2 GetBranchCodeFromBorrowers
1378
1379 =over 4
1380
1381 $sth = GetBranchCodeFromBorrowers();
1382
1383 this function just prepare the SQL request.
1384 After this function, don't forget to execute it by using $sth->execute($borrowernumber)
1385 return :
1386 $sth = $dbh->prepare($query).
1387
1388 =back
1389
1390 =cut
1391 sub GetBranchCodeFromBorrowers {
1392     my $dbh = C4::Context->dbh;
1393     my $query = qq|
1394         SELECT flags, branchcode
1395         FROM   borrowers
1396         WHERE  borrowernumber = ?
1397     |;
1398     return $dbh->prepare($query);
1399 }
1400 END { }       # module clean-up code here (global destructor)
1401
1402 1;