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